Bug 1126607, part 1: Import the LDAP C-SDK into comm-central.
authorhg@mozilla.org
Sun, 19 Apr 2015 22:20:33 -0500
changeset 17814 f9f973c875f8e70cdb12586f50c5799419c31c07
parent 17813 0f3e3aae3ef2b4db95b3fff4efb4a6a9655a5d27
child 17815 2b00be2ded7f6b20d5b10523f73ff29bb02edd43
push id10956
push userPidgeot18@gmail.com
push dateMon, 20 Apr 2015 03:31:17 +0000
treeherdercomm-central@24203ada3e1e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1126607
Bug 1126607, part 1: Import the LDAP C-SDK into comm-central. This code is generated by finding all .c, .h, and relevent Makefile.in files in the relevant files of c-sdk/ldap from http://hg.mozilla.org/projects/ldap-sdks/, as of LDAPCSDK_6_0_7G_RTM. The file directories are re-mapped in the import to avoid needing to do extensive clobbering of the source and build directories. No other changes are done in this changeset, and the imported code is not integrated into the build system.
ldap/c-sdk/include/Makefile.in
ldap/c-sdk/include/disptmpl.h
ldap/c-sdk/include/iutil.h
ldap/c-sdk/include/lber.h
ldap/c-sdk/include/lcache.h
ldap/c-sdk/include/ldap-deprecated.h
ldap/c-sdk/include/ldap-extension.h
ldap/c-sdk/include/ldap-platform.h
ldap/c-sdk/include/ldap-standard-tmpl.h
ldap/c-sdk/include/ldap-to-be-deprecated.h
ldap/c-sdk/include/ldap.h
ldap/c-sdk/include/ldap_ssl.h
ldap/c-sdk/include/ldaplog.h
ldap/c-sdk/include/ldappr.h
ldap/c-sdk/include/ldaprot.h
ldap/c-sdk/include/ldif.h
ldap/c-sdk/include/portable.h
ldap/c-sdk/include/proto-ntutil.h
ldap/c-sdk/include/regex.h
ldap/c-sdk/include/srchpref.h
ldap/c-sdk/libraries/libiutil/Makefile.in
ldap/c-sdk/libraries/libiutil/iutil-lock.c
ldap/c-sdk/libraries/liblber/Makefile.in
ldap/c-sdk/libraries/liblber/bprint.c
ldap/c-sdk/libraries/liblber/decode.c
ldap/c-sdk/libraries/liblber/dtest.c
ldap/c-sdk/libraries/liblber/encode.c
ldap/c-sdk/libraries/liblber/etest.c
ldap/c-sdk/libraries/liblber/idtest.c
ldap/c-sdk/libraries/liblber/io.c
ldap/c-sdk/libraries/liblber/lber-int.h
ldap/c-sdk/libraries/libldap/Makefile.in
ldap/c-sdk/libraries/libldap/abandon.c
ldap/c-sdk/libraries/libldap/add.c
ldap/c-sdk/libraries/libldap/authzidctrl.c
ldap/c-sdk/libraries/libldap/bind.c
ldap/c-sdk/libraries/libldap/cache.c
ldap/c-sdk/libraries/libldap/charray.c
ldap/c-sdk/libraries/libldap/charset.c
ldap/c-sdk/libraries/libldap/cldap.c
ldap/c-sdk/libraries/libldap/compare.c
ldap/c-sdk/libraries/libldap/compat.c
ldap/c-sdk/libraries/libldap/control.c
ldap/c-sdk/libraries/libldap/countvalues.c
ldap/c-sdk/libraries/libldap/delete.c
ldap/c-sdk/libraries/libldap/disptmpl.c
ldap/c-sdk/libraries/libldap/dllmain.c
ldap/c-sdk/libraries/libldap/dsparse.c
ldap/c-sdk/libraries/libldap/error.c
ldap/c-sdk/libraries/libldap/extendop.c
ldap/c-sdk/libraries/libldap/free.c
ldap/c-sdk/libraries/libldap/freevalues.c
ldap/c-sdk/libraries/libldap/friendly.c
ldap/c-sdk/libraries/libldap/getattr.c
ldap/c-sdk/libraries/libldap/getdn.c
ldap/c-sdk/libraries/libldap/getdxbyname.c
ldap/c-sdk/libraries/libldap/geteffectiverightsctrl.c
ldap/c-sdk/libraries/libldap/getentry.c
ldap/c-sdk/libraries/libldap/getfilter.c
ldap/c-sdk/libraries/libldap/getoption.c
ldap/c-sdk/libraries/libldap/getvalues.c
ldap/c-sdk/libraries/libldap/ldap-int.h
ldap/c-sdk/libraries/libldap/memcache.c
ldap/c-sdk/libraries/libldap/message.c
ldap/c-sdk/libraries/libldap/modify.c
ldap/c-sdk/libraries/libldap/mozock.c
ldap/c-sdk/libraries/libldap/nsprthreadtest.c
ldap/c-sdk/libraries/libldap/open.c
ldap/c-sdk/libraries/libldap/os-ip.c
ldap/c-sdk/libraries/libldap/proxyauthctrl.c
ldap/c-sdk/libraries/libldap/psearch.c
ldap/c-sdk/libraries/libldap/pthreadtest.c
ldap/c-sdk/libraries/libldap/pwmodext.c
ldap/c-sdk/libraries/libldap/pwpctrl.c
ldap/c-sdk/libraries/libldap/referral.c
ldap/c-sdk/libraries/libldap/regex.c
ldap/c-sdk/libraries/libldap/rename.c
ldap/c-sdk/libraries/libldap/request.c
ldap/c-sdk/libraries/libldap/reslist.c
ldap/c-sdk/libraries/libldap/result.c
ldap/c-sdk/libraries/libldap/saslbind.c
ldap/c-sdk/libraries/libldap/saslio.c
ldap/c-sdk/libraries/libldap/sbind.c
ldap/c-sdk/libraries/libldap/search.c
ldap/c-sdk/libraries/libldap/setoption.c
ldap/c-sdk/libraries/libldap/sort.c
ldap/c-sdk/libraries/libldap/sortctrl.c
ldap/c-sdk/libraries/libldap/srchpref.c
ldap/c-sdk/libraries/libldap/test.c
ldap/c-sdk/libraries/libldap/tmplout.c
ldap/c-sdk/libraries/libldap/tmpltest.c
ldap/c-sdk/libraries/libldap/ufn.c
ldap/c-sdk/libraries/libldap/unbind.c
ldap/c-sdk/libraries/libldap/unescape.c
ldap/c-sdk/libraries/libldap/url.c
ldap/c-sdk/libraries/libldap/userstatusctrl.c
ldap/c-sdk/libraries/libldap/utf8.c
ldap/c-sdk/libraries/libldap/vlistctrl.c
ldap/c-sdk/libraries/libldap/whoami.c
ldap/c-sdk/libraries/libldif/Makefile.in
ldap/c-sdk/libraries/libldif/line64.c
ldap/c-sdk/libraries/libprldap/Makefile.in
ldap/c-sdk/libraries/libprldap/ldappr-dns.c
ldap/c-sdk/libraries/libprldap/ldappr-error.c
ldap/c-sdk/libraries/libprldap/ldappr-int.h
ldap/c-sdk/libraries/libprldap/ldappr-io.c
ldap/c-sdk/libraries/libprldap/ldappr-public.c
ldap/c-sdk/libraries/libprldap/ldappr-threads.c
ldap/c-sdk/libraries/libutil/Makefile.in
ldap/c-sdk/libraries/libutil/getopt.c
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/include/Makefile.in
@@ -0,0 +1,104 @@
+# 
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+# 
+# The contents of this file are subject to the Mozilla Public License Version 
+# 1.1 (the "License"); you may not use this file except in compliance with 
+# the License. You may obtain a copy of the License at 
+# http://www.mozilla.org/MPL/
+# 
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+# 
+# The Original Code is Mozilla Communicator client code, released
+# March 31, 1998.
+# 
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 1998-1999
+# the Initial Developer. All Rights Reserved.
+# 
+# Contributor(s):
+# 
+# Alternatively, the contents of this file may be used under the terms of
+# either of the GNU General Public License Version 2 or later (the "GPL"),
+# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+# 
+# ***** END LICENSE BLOCK ***** 
+
+MOD_DEPTH	= ../..
+srcdir		= @srcdir@
+topsrcdir	= @top_srcdir@
+
+include $(MOD_DEPTH)/config/autoconf.mk
+include $(topsrcdir)/build.mk
+
+CHMOD		= chmod
+RM		= rm -f
+SED		= sed
+
+HEADERS		= \
+		  disptmpl.h \
+		  lber.h \
+		  ldap.h \
+		  ldap-extension.h \
+		  ldap-platform.h \
+		  ldap-to-be-deprecated.h \
+		  ldap-deprecated.h \
+		  ldap_ssl.h \
+		  ldappr.h \
+		  ldif.h \
+		  iutil.h \
+		  srchpref.h \
+		  $(NULL)
+HEADERS := $(addprefix $(srcdir)/, $(HEADERS))
+
+PRIVATEHEADERS	= \
+		  ../libraries/libldap/ldap-int.h \
+		  ../libraries/liblber/lber-int.h \
+		  portable.h \
+		  ldaprot.h \
+		  ldaplog.h \
+		  $(NULL)
+PRIVATEHEADERS := $(addprefix $(srcdir)/, $(PRIVATEHEADERS))
+
+LDAP_STD_HEADER = ldap-standard.h
+
+RELEASE_HEADERS	= $(HEADERS) $(LDAP_STD_HEADER)
+
+include $(topsrcdir)/config/rules.mk
+
+INCLUDEDIR	= $(DIST)/public/ldap
+PRIVATEINCDIR	= $(DIST)/public/ldap-private
+
+GARBAGE		+= sdkver.h dirver.h $(LDAP_STD_HEADER)
+
+###########################################################################
+
+all export:: $(INCLUDEDIR) $(LDAP_STD_HEADER)
+	$(NSINSTALL) -D $(PRIVATEINCDIR)
+	$(INSTALL) $(INSTALLFLAGS) -m 644 $(HEADERS) $(LDAP_STD_HEADER) $(INCLUDEDIR)
+	$(INSTALL) $(INSTALLFLAGS) -m 644 $(PRIVATEHEADERS) $(PRIVATEINCDIR)
+
+$(INCLUDEDIR):	FORCE
+	$(NSINSTALL) -D $(INCLUDEDIR)
+
+
+$(LDAP_STD_HEADER): ldap-standard-tmpl.h
+	$(PERL) $(srcdir)/../build/replace.pl \
+			LDAP_VENDOR_NAME="$(VENDOR_NAME)" \
+			LDAP_VENDOR_VERSION="$(VENDOR_VERSION)" \
+			< $< > $@
+
+FORCE:
+
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/include/disptmpl.h
@@ -0,0 +1,379 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Copyright (c) 1993, 1994 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ *
+ * disptmpl.h:  display template library defines
+ */
+
+#ifndef _DISPTMPL_H
+#define _DISPTMPL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* calling conventions used by library */
+#ifndef LDAP_CALL
+#if defined( _WINDOWS ) || defined( _WIN32 )
+#define LDAP_C __cdecl
+#ifndef _WIN32 
+#define __stdcall _far _pascal
+#define LDAP_CALLBACK _loadds
+#else
+#define LDAP_CALLBACK
+#endif /* _WIN32 */
+#define LDAP_PASCAL __stdcall
+#define LDAP_CALL LDAP_PASCAL
+#else /* _WINDOWS */
+#define LDAP_C
+#define LDAP_CALLBACK
+#define LDAP_PASCAL
+#define LDAP_CALL
+#endif /* _WINDOWS */
+#endif /* LDAP_CALL */
+
+#define LDAP_TEMPLATE_VERSION	1
+
+/*
+ * general types of items (confined to most significant byte)
+ */
+#define LDAP_SYN_TYPE_TEXT		0x01000000L
+#define LDAP_SYN_TYPE_IMAGE		0x02000000L
+#define LDAP_SYN_TYPE_BOOLEAN		0x04000000L
+#define LDAP_SYN_TYPE_BUTTON		0x08000000L
+#define LDAP_SYN_TYPE_ACTION		0x10000000L
+
+
+/*
+ * syntax options (confined to second most significant byte)
+ */
+#define LDAP_SYN_OPT_DEFER		0x00010000L
+
+
+/* 
+ * display template item syntax ids (defined by common agreement)
+ * these are the valid values for the ti_syntaxid of the tmplitem
+ * struct (defined below).  A general type is encoded in the
+ * most-significant 8 bits, and some options are encoded in the next
+ * 8 bits.  The lower 16 bits are reserved for the distinct types.
+ */
+#define LDAP_SYN_CASEIGNORESTR	( 1 | LDAP_SYN_TYPE_TEXT )
+#define LDAP_SYN_MULTILINESTR	( 2 | LDAP_SYN_TYPE_TEXT )
+#define LDAP_SYN_DN		( 3 | LDAP_SYN_TYPE_TEXT )
+#define LDAP_SYN_BOOLEAN	( 4 | LDAP_SYN_TYPE_BOOLEAN )
+#define LDAP_SYN_JPEGIMAGE	( 5 | LDAP_SYN_TYPE_IMAGE )
+#define LDAP_SYN_JPEGBUTTON	( 6 | LDAP_SYN_TYPE_BUTTON | LDAP_SYN_OPT_DEFER )
+#define LDAP_SYN_FAXIMAGE	( 7 | LDAP_SYN_TYPE_IMAGE )
+#define LDAP_SYN_FAXBUTTON	( 8 | LDAP_SYN_TYPE_BUTTON | LDAP_SYN_OPT_DEFER )
+#define LDAP_SYN_AUDIOBUTTON	( 9 | LDAP_SYN_TYPE_BUTTON | LDAP_SYN_OPT_DEFER )
+#define LDAP_SYN_TIME		( 10 | LDAP_SYN_TYPE_TEXT )
+#define LDAP_SYN_DATE		( 11 | LDAP_SYN_TYPE_TEXT )
+#define LDAP_SYN_LABELEDURL	( 12 | LDAP_SYN_TYPE_TEXT )
+#define LDAP_SYN_SEARCHACTION	( 13 | LDAP_SYN_TYPE_ACTION )
+#define LDAP_SYN_LINKACTION	( 14 | LDAP_SYN_TYPE_ACTION )
+#define LDAP_SYN_ADDDNACTION	( 15 | LDAP_SYN_TYPE_ACTION )
+#define LDAP_SYN_VERIFYDNACTION ( 16 | LDAP_SYN_TYPE_ACTION )
+#define LDAP_SYN_RFC822ADDR	( 17 | LDAP_SYN_TYPE_TEXT )
+
+
+/*
+ * handy macros
+ */
+#define LDAP_GET_SYN_TYPE( syid )	((syid) & 0xFF000000UL )
+#define LDAP_GET_SYN_OPTIONS( syid )	((syid) & 0x00FF0000UL )
+
+
+/*
+ * display options for output routines (used by entry2text and friends)
+ */
+/*
+ * use calculated label width (based on length of longest label in
+ * template) instead of contant width
+ */
+#define LDAP_DISP_OPT_AUTOLABELWIDTH	0x00000001L
+#define LDAP_DISP_OPT_HTMLBODYONLY	0x00000002L
+
+/*
+ * perform search actions (applies to ldap_entry2text_search only) 
+ */
+#define LDAP_DISP_OPT_DOSEARCHACTIONS	0x00000002L
+
+/*
+ * include additional info. relevant to "non leaf" entries only
+ * used by ldap_entry2html and ldap_entry2html_search to include "Browse"
+ * and "Move Up" HREFs
+ */
+#define LDAP_DISP_OPT_NONLEAF		0x00000004L
+
+
+/*
+ * display template item options (may not apply to all types)
+ * if this bit is set in ti_options, it applies.
+ */
+#define LDAP_DITEM_OPT_READONLY		0x00000001L
+#define LDAP_DITEM_OPT_SORTVALUES	0x00000002L
+#define LDAP_DITEM_OPT_SINGLEVALUED	0x00000004L
+#define LDAP_DITEM_OPT_HIDEIFEMPTY	0x00000008L
+#define LDAP_DITEM_OPT_VALUEREQUIRED	0x00000010L
+#define LDAP_DITEM_OPT_HIDEIFFALSE	0x00000020L	/* booleans only */
+
+
+
+/*
+ * display template item structure
+ */
+struct ldap_tmplitem {
+    unsigned long		ti_syntaxid;
+    unsigned long		ti_options;
+    char  			*ti_attrname;
+    char			*ti_label;
+    char			**ti_args;
+    struct ldap_tmplitem	*ti_next_in_row;
+    struct ldap_tmplitem	*ti_next_in_col;
+    void			*ti_appdata;
+};
+
+
+#define NULLTMPLITEM	((struct ldap_tmplitem *)0)
+
+#define LDAP_SET_TMPLITEM_APPDATA( ti, datap )	\
+	(ti)->ti_appdata = (void *)(datap)
+
+#define LDAP_GET_TMPLITEM_APPDATA( ti, type )	\
+	(type)((ti)->ti_appdata)
+
+#define LDAP_IS_TMPLITEM_OPTION_SET( ti, option )	\
+	(((ti)->ti_options & option ) != 0 )
+
+
+/*
+ * object class array structure
+ */
+struct ldap_oclist {
+    char		**oc_objclasses;
+    struct ldap_oclist	*oc_next;
+};
+
+#define NULLOCLIST	((struct ldap_oclist *)0)
+
+
+/*
+ * add defaults list
+ */
+struct ldap_adddeflist {
+    int			ad_source;
+#define LDAP_ADSRC_CONSTANTVALUE	1
+#define LDAP_ADSRC_ADDERSDN		2
+    char		*ad_attrname;
+    char		*ad_value;
+    struct ldap_adddeflist	*ad_next;
+};
+
+#define NULLADLIST	((struct ldap_adddeflist *)0)
+
+
+/*
+ * display template global options
+ * if this bit is set in dt_options, it applies.
+ */
+/*
+ * users should be allowed to try to add objects of these entries
+ */
+#define LDAP_DTMPL_OPT_ADDABLE		0x00000001L
+
+/*
+ * users should be allowed to do "modify RDN" operation of these entries
+ */
+#define LDAP_DTMPL_OPT_ALLOWMODRDN	0x00000002L
+
+/*
+ * this template is an alternate view, not a primary view
+ */
+#define LDAP_DTMPL_OPT_ALTVIEW		0x00000004L
+
+
+/*
+ * display template structure
+ */
+struct ldap_disptmpl {
+    char			*dt_name;
+    char			*dt_pluralname;
+    char			*dt_iconname;
+    unsigned long		dt_options;
+    char			*dt_authattrname;
+    char			*dt_defrdnattrname;
+    char			*dt_defaddlocation;
+    struct ldap_oclist		*dt_oclist;
+    struct ldap_adddeflist	*dt_adddeflist;
+    struct ldap_tmplitem	*dt_items;
+    void			*dt_appdata;
+    struct ldap_disptmpl	*dt_next;
+};
+
+#define NULLDISPTMPL	((struct ldap_disptmpl *)0)
+
+#define LDAP_SET_DISPTMPL_APPDATA( dt, datap )	\
+	(dt)->dt_appdata = (void *)(datap)
+
+#define LDAP_GET_DISPTMPL_APPDATA( dt, type )	\
+	(type)((dt)->dt_appdata)
+
+#define LDAP_IS_DISPTMPL_OPTION_SET( dt, option )	\
+	(((dt)->dt_options & option ) != 0 )
+
+#define LDAP_TMPL_ERR_VERSION	1
+#define LDAP_TMPL_ERR_MEM	2
+#define LDAP_TMPL_ERR_SYNTAX	3
+#define LDAP_TMPL_ERR_FILE	4
+
+/*
+ * buffer size needed for entry2text and vals2text
+ */
+#define LDAP_DTMPL_BUFSIZ	8192
+
+typedef int (*writeptype)( void *writeparm, char *p, int len );
+
+LDAP_API(int)
+LDAP_CALL
+ldap_init_templates( char *file, struct ldap_disptmpl **tmpllistp );
+
+LDAP_API(int)
+LDAP_CALL
+ldap_init_templates_buf( char *buf, long buflen,
+	struct ldap_disptmpl **tmpllistp );
+
+LDAP_API(void)
+LDAP_CALL
+ldap_free_templates( struct ldap_disptmpl *tmpllist );
+
+LDAP_API(struct ldap_disptmpl *)
+LDAP_CALL
+ldap_first_disptmpl( struct ldap_disptmpl *tmpllist );
+
+LDAP_API(struct ldap_disptmpl *)
+LDAP_CALL
+ldap_next_disptmpl( struct ldap_disptmpl *tmpllist,
+	struct ldap_disptmpl *tmpl );
+
+LDAP_API(struct ldap_disptmpl *)
+LDAP_CALL
+ldap_name2template( char *name, struct ldap_disptmpl *tmpllist );
+
+LDAP_API(struct ldap_disptmpl *)
+LDAP_CALL
+ldap_oc2template( char **oclist, struct ldap_disptmpl *tmpllist );
+
+LDAP_API(char **)
+LDAP_CALL
+ldap_tmplattrs( struct ldap_disptmpl *tmpl, char **includeattrs, int exclude,
+	 unsigned long syntaxmask );
+
+LDAP_API(struct ldap_tmplitem *)
+LDAP_CALL
+ldap_first_tmplrow( struct ldap_disptmpl *tmpl );
+
+LDAP_API(struct ldap_tmplitem *)
+LDAP_CALL
+ldap_next_tmplrow( struct ldap_disptmpl *tmpl, struct ldap_tmplitem *row );
+
+LDAP_API(struct ldap_tmplitem *)
+LDAP_CALL
+ldap_first_tmplcol( struct ldap_disptmpl *tmpl, struct ldap_tmplitem *row );
+
+LDAP_API(struct ldap_tmplitem *)
+LDAP_CALL
+ldap_next_tmplcol( struct ldap_disptmpl *tmpl, struct ldap_tmplitem *row,
+	struct ldap_tmplitem *col );
+
+LDAP_API(int)
+LDAP_CALL
+ldap_entry2text( LDAP *ld, char *buf, LDAPMessage *entry,
+	struct ldap_disptmpl *tmpl, char **defattrs, char ***defvals,
+	writeptype writeproc, void *writeparm, char *eol, int rdncount,
+	unsigned long opts );
+
+LDAP_API(int)
+LDAP_CALL
+ldap_vals2text( LDAP *ld, char *buf, char **vals, char *label, int labelwidth,
+	unsigned long syntaxid, writeptype writeproc, void *writeparm,
+	char *eol, int rdncount );
+
+LDAP_API(int)
+LDAP_CALL
+ldap_entry2text_search( LDAP *ld, char *dn, char *base, LDAPMessage *entry,
+	struct ldap_disptmpl *tmpllist, char **defattrs, char ***defvals,
+	writeptype writeproc, void *writeparm, char *eol, int rdncount,
+	unsigned long opts );
+
+LDAP_API(int)
+LDAP_CALL
+ldap_entry2html( LDAP *ld, char *buf, LDAPMessage *entry,
+	struct ldap_disptmpl *tmpl, char **defattrs, char ***defvals,
+	writeptype writeproc, void *writeparm, char *eol, int rdncount,
+	unsigned long opts, char *urlprefix, char *base );
+
+LDAP_API(int)
+LDAP_CALL
+ldap_vals2html( LDAP *ld, char *buf, char **vals, char *label, int labelwidth,
+	unsigned long syntaxid, writeptype writeproc, void *writeparm,
+	char *eol, int rdncount, char *urlprefix );
+
+LDAP_API(int)
+LDAP_CALL
+ldap_entry2html_search( LDAP *ld, char *dn, char *base, LDAPMessage *entry,
+	struct ldap_disptmpl *tmpllist, char **defattrs, char ***defvals,
+	writeptype writeproc, void *writeparm, char *eol, int rdncount,
+	unsigned long opts, char *urlprefix );
+
+LDAP_API(char *)
+LDAP_CALL
+ldap_tmplerr2string( int err );
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _DISPTMPL_H */
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/include/iutil.h
@@ -0,0 +1,72 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Interface for libiutil the innosoft migration library
+ *
+ */
+
+#ifndef _IUTIL_H
+#define _IUTIL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* from iutil-lock.c */
+
+#ifdef _WINDOWS
+#define LDAP_MUTEX_T HANDLE
+
+extern		char *ldap_strdup();
+extern		unsigned char *ldap_utf8_nextchar();
+extern		char **ldap_explode_ava();
+extern		int ldap_utf8_toupper();
+
+int		pthread_mutex_init( LDAP_MUTEX_T *mp, void *attr);
+static void  *	pthread_mutex_alloc( void );
+int		pthread_mutex_destroy( LDAP_MUTEX_T *mp );
+static void	pthread_mutex_free( void *mutexp );
+int		pthread_mutex_lock( LDAP_MUTEX_T *mp );
+int		pthread_mutex_unlock( LDAP_MUTEX_T *mp );
+
+#endif /* _WINDOWS */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* _IUTIL_H */
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/include/lber.h
@@ -0,0 +1,339 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/* lber.h - header file for ber_* functions */
+#ifndef _LBER_H
+#define _LBER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>	/* to pick up size_t typedef */
+
+/*
+ * Note that LBER_ERROR and LBER_DEFAULT are values that can never appear
+ * as valid BER tags, and so it is safe to use them to report errors.  In
+ * fact, any tag for which the following is true is invalid:
+ *     (( tag & 0x00000080 ) != 0 ) && (( tag & 0xFFFFFF00 ) != 0 )
+ */
+#define LBER_ERROR              ((ber_tag_t) -1) /* 0xffffffffU */
+#define LBER_DEFAULT            ((ber_tag_t) -1) /* 0xffffffffU */	
+#define LBER_END_OF_SEQORSET    ((ber_tag_t) -2) /* 0xfffffffeU */
+#define LBER_OVERFLOW           ((ber_tag_t) -3) /* 0xfffffffdU */
+
+/* BER classes and mask */
+#define LBER_CLASS_UNIVERSAL    0x00
+#define LBER_CLASS_APPLICATION  0x40
+#define LBER_CLASS_CONTEXT      0x80
+#define LBER_CLASS_PRIVATE      0xc0
+#define LBER_CLASS_MASK         0xc0
+
+/* BER encoding type and mask */
+#define LBER_PRIMITIVE          0x00
+#define LBER_CONSTRUCTED        0x20
+#define LBER_ENCODING_MASK      0x20
+
+#define LBER_BIG_TAG_MASK       0x1f
+#define LBER_MORE_TAG_MASK      0x80
+
+/* general BER types we know about */
+#define LBER_BOOLEAN		0x01
+#define LBER_INTEGER		0x02
+#define LBER_BITSTRING		0x03
+#define LBER_OCTETSTRING	0x04
+#define LBER_NULL			0x05
+#define LBER_ENUMERATED		0x0a
+#define LBER_SEQUENCE		0x30
+#define LBER_SET			0x31
+
+/* BerElement set/get options */
+#define LBER_OPT_REMAINING_BYTES	0x01
+#define LBER_OPT_TOTAL_BYTES		0x02
+#define LBER_OPT_USE_DER			0x04
+#define LBER_OPT_TRANSLATE_STRINGS	0x08
+#define LBER_OPT_BYTES_TO_WRITE		0x10
+#define LBER_OPT_MEMALLOC_FN_PTRS	0x20
+#define LBER_OPT_DEBUG_LEVEL		0x40
+#define LBER_OPT_BUFSIZE			0x80
+
+/*
+ * LBER_USE_DER is defined for compatibility with the C LDAP API RFC.
+ * In our implementation, we recognize it (instead of the numerically
+ * identical LBER_OPT_REMAINING_BYTES) in calls to ber_alloc_t() and 
+ * ber_init_w_nullchar() only.  Callers of ber_set_option() or
+ * ber_get_option() must use LBER_OPT_USE_DER instead.  Sorry!
+ */
+#define LBER_USE_DER			0x01
+
+/* Sockbuf set/get options */
+#define LBER_SOCKBUF_OPT_TO_FILE			0x001
+#define LBER_SOCKBUF_OPT_TO_FILE_ONLY		0x002
+#define LBER_SOCKBUF_OPT_MAX_INCOMING_SIZE	0x004
+#define LBER_SOCKBUF_OPT_NO_READ_AHEAD		0x008
+#define LBER_SOCKBUF_OPT_DESC				0x010
+#define LBER_SOCKBUF_OPT_COPYDESC			0x020
+#define LBER_SOCKBUF_OPT_READ_FN			0x040
+#define LBER_SOCKBUF_OPT_WRITE_FN			0x080
+#define LBER_SOCKBUF_OPT_EXT_IO_FNS			0x100
+#define	LBER_SOCKBUF_OPT_VALID_TAG			0x200
+#define LBER_SOCKBUF_OPT_SOCK_ARG			0x400
+
+#define LBER_OPT_ON	((void *) 1)
+#define LBER_OPT_OFF	((void *) 0)
+
+typedef unsigned int	ber_len_t;   /* for BER len */
+typedef unsigned int	ber_tag_t;   /* for BER tags */
+typedef int				ber_int_t;   /* for BER ints, enums, and Booleans */
+typedef unsigned int	ber_uint_t; /* unsigned equivalent of ber_int_t */
+typedef int				ber_slen_t; /* signed equivalent of ber_len_t */
+
+typedef struct berval {
+	ber_len_t	bv_len;
+	char		*bv_val;
+} BerValue;
+
+typedef struct berelement BerElement;
+typedef struct sockbuf Sockbuf;
+typedef int (*BERTranslateProc)( char **bufp, ber_uint_t *buflenp,
+	int free_input );
+#ifndef macintosh
+#if defined( _WINDOWS ) || defined( _WIN32) || defined( _CONSOLE )
+#include <winsock.h> /* for SOCKET */
+typedef SOCKET LBER_SOCKET;
+#else
+typedef long LBER_SOCKET;
+#endif /* _WINDOWS */
+#else /* macintosh */
+typedef void *LBER_SOCKET;
+#endif /* macintosh */
+
+/* calling conventions used by library */
+#ifndef LDAP_CALL
+#if defined( _WINDOWS ) || defined( _WIN32 )
+#define LDAP_C __cdecl
+#ifndef _WIN32 
+#define __stdcall _far _pascal
+#define LDAP_CALLBACK _loadds
+#else
+#define LDAP_CALLBACK
+#endif /* _WIN32 */
+#define LDAP_PASCAL __stdcall
+#define LDAP_CALL LDAP_PASCAL
+#else /* _WINDOWS */
+#define LDAP_C
+#define LDAP_CALLBACK
+#define LDAP_PASCAL
+#define LDAP_CALL
+#endif /* _WINDOWS */
+#endif /* LDAP_CALL */
+
+/*
+ * function prototypes for lber library
+ */
+
+#ifndef LDAP_API
+#if defined( _WINDOWS ) || defined( _WIN32 )
+#define LDAP_API(rt) rt
+#else /* _WINDOWS */
+#define LDAP_API(rt) rt
+#endif /* _WINDOWS */
+#endif /* LDAP_API */
+
+struct lextiof_socket_private;          /* Defined by the extended I/O */
+                                        /* callback functions */
+struct lextiof_session_private;         /* Defined by the extended I/O */
+                                        /* callback functions */
+
+/* This is modeled after the PRIOVec that is passed to the NSPR
+   writev function! The void* is a char* in that struct */
+typedef struct ldap_x_iovec {
+        char    *ldapiov_base;
+        int     ldapiov_len;
+} ldap_x_iovec;
+
+/*
+ * libldap read and write I/O function callbacks.  The rest of the I/O callback
+ * types are defined in ldap.h
+ */
+typedef int (LDAP_C LDAP_CALLBACK LDAP_IOF_READ_CALLBACK)( LBER_SOCKET s,
+	void *buf, int bufsize );
+typedef int (LDAP_C LDAP_CALLBACK LDAP_IOF_WRITE_CALLBACK)( LBER_SOCKET s,
+	const void *buf, int len );
+typedef int (LDAP_C LDAP_CALLBACK LDAP_X_EXTIOF_READ_CALLBACK)( int s,
+	void *buf, int bufsize, struct lextiof_socket_private *socketarg );
+typedef int (LDAP_C LDAP_CALLBACK LDAP_X_EXTIOF_WRITE_CALLBACK)( int s,
+	const void *buf, int len, struct lextiof_socket_private *socketarg );
+typedef int (LDAP_C LDAP_CALLBACK LDAP_X_EXTIOF_WRITEV_CALLBACK)(int s,
+	const ldap_x_iovec iov[], int iovcnt, struct lextiof_socket_private *socketarg);
+						     
+
+/*
+ * Structure for use with LBER_SOCKBUF_OPT_EXT_IO_FNS:
+ */
+struct lber_x_ext_io_fns {
+	    /* lbextiofn_size should always be set to LBER_X_EXTIO_FNS_SIZE */
+	int				lbextiofn_size;
+	LDAP_X_EXTIOF_READ_CALLBACK	*lbextiofn_read;
+	LDAP_X_EXTIOF_WRITE_CALLBACK	*lbextiofn_write;
+	struct lextiof_socket_private	*lbextiofn_socket_arg;
+        LDAP_X_EXTIOF_WRITEV_CALLBACK   *lbextiofn_writev;
+};
+#define LBER_X_EXTIO_FNS_SIZE sizeof(struct lber_x_ext_io_fns)
+
+/*
+ * liblber memory allocation callback functions.  These are global to all
+ *  Sockbufs and BerElements.  Install your own functions by using a call
+ *  like this: ber_set_option( NULL, LBER_OPT_MEMALLOC_FN_PTRS, &memalloc_fns );
+ */
+typedef void * (LDAP_C LDAP_CALLBACK LDAP_MALLOC_CALLBACK)( size_t size );
+typedef void * (LDAP_C LDAP_CALLBACK LDAP_CALLOC_CALLBACK)( size_t nelem,
+	size_t elsize );
+typedef void * (LDAP_C LDAP_CALLBACK LDAP_REALLOC_CALLBACK)( void *ptr,
+	size_t size );
+typedef void (LDAP_C LDAP_CALLBACK LDAP_FREE_CALLBACK)( void *ptr );
+
+struct lber_memalloc_fns {
+	LDAP_MALLOC_CALLBACK	*lbermem_malloc;
+	LDAP_CALLOC_CALLBACK	*lbermem_calloc;
+	LDAP_REALLOC_CALLBACK	*lbermem_realloc;
+	LDAP_FREE_CALLBACK	*lbermem_free;
+};
+
+/*
+ * decode routines
+ */
+LDAP_API(ber_tag_t) LDAP_CALL ber_get_tag( BerElement *ber );
+LDAP_API(ber_tag_t) LDAP_CALL ber_skip_tag( BerElement *ber, 
+	ber_len_t *len );
+LDAP_API(ber_tag_t) LDAP_CALL ber_peek_tag( BerElement *ber, 
+	ber_len_t *len );
+LDAP_API(ber_tag_t) LDAP_CALL ber_get_int( BerElement *ber, ber_int_t *num );
+LDAP_API(ber_tag_t) LDAP_CALL ber_get_stringb( BerElement *ber, char *buf,
+	ber_len_t *len );
+LDAP_API(ber_tag_t) LDAP_CALL ber_get_stringa( BerElement *ber, 
+	char **buf );
+LDAP_API(ber_tag_t) LDAP_CALL ber_get_stringal( BerElement *ber,
+	struct berval **bv );
+LDAP_API(ber_tag_t) LDAP_CALL ber_get_bitstringa( BerElement *ber, 
+	char **buf, ber_len_t *len );
+LDAP_API(ber_tag_t) LDAP_CALL ber_get_null( BerElement *ber );
+LDAP_API(ber_tag_t) LDAP_CALL ber_get_boolean( BerElement *ber, 
+	ber_int_t *boolval );
+LDAP_API(ber_tag_t) LDAP_CALL ber_first_element( BerElement *ber,
+	ber_len_t *len, char **last );
+LDAP_API(ber_tag_t) LDAP_CALL ber_next_element( BerElement *ber,
+	ber_len_t *len, char *last );
+LDAP_API(ber_tag_t) LDAP_C ber_scanf( BerElement *ber, const char *fmt,
+	... );
+LDAP_API(void) LDAP_CALL ber_bvfree( struct berval *bv );
+LDAP_API(void) LDAP_CALL ber_bvecfree( struct berval **bv );
+LDAP_API(void) LDAP_CALL ber_svecfree( char **vals );
+LDAP_API(struct berval *) LDAP_CALL ber_bvdup( const struct berval *bv );
+LDAP_API(void) LDAP_CALL ber_set_string_translators( BerElement *ber,
+	BERTranslateProc encode_proc, BERTranslateProc decode_proc );
+LDAP_API(BerElement *) LDAP_CALL ber_init( const struct berval *bv );
+
+/*
+ * encoding routines
+ */
+LDAP_API(int) LDAP_CALL ber_put_enum( BerElement *ber, ber_int_t num, 
+	ber_tag_t tag );
+LDAP_API(int) LDAP_CALL ber_put_int( BerElement *ber, ber_int_t num, 
+	ber_tag_t tag );
+LDAP_API(int) LDAP_CALL ber_put_ostring( BerElement *ber, char *str, 
+	ber_len_t len, ber_tag_t tag );
+LDAP_API(int) LDAP_CALL ber_put_string( BerElement *ber, char *str,
+	ber_tag_t tag );
+LDAP_API(int) LDAP_CALL ber_put_bitstring( BerElement *ber, char *str,
+	ber_len_t bitlen, ber_tag_t tag );
+LDAP_API(int) LDAP_CALL ber_put_null( BerElement *ber, ber_tag_t tag );
+LDAP_API(int) LDAP_CALL ber_put_boolean( BerElement *ber, 
+	ber_int_t boolval, ber_tag_t tag );
+LDAP_API(int) LDAP_CALL ber_start_seq( BerElement *ber, ber_tag_t tag );
+LDAP_API(int) LDAP_CALL ber_start_set( BerElement *ber, ber_tag_t tag );
+LDAP_API(int) LDAP_CALL ber_put_seq( BerElement *ber );
+LDAP_API(int) LDAP_CALL ber_put_set( BerElement *ber );
+LDAP_API(int) LDAP_C ber_printf( BerElement *ber, const char *fmt, ... );
+LDAP_API(int) LDAP_CALL ber_flatten( BerElement *ber,
+	struct berval **bvPtr );
+
+/*
+ * miscellaneous routines
+ */
+LDAP_API(void) LDAP_CALL ber_free( BerElement *ber, int freebuf );
+LDAP_API(void) LDAP_CALL ber_special_free(void* buf, BerElement *ber);
+LDAP_API(int) LDAP_CALL ber_flush( Sockbuf *sb, BerElement *ber, int freeit );
+LDAP_API(BerElement*) LDAP_CALL ber_alloc( void );
+LDAP_API(BerElement*) LDAP_CALL der_alloc( void );
+LDAP_API(BerElement*) LDAP_CALL ber_alloc_t( int options );
+LDAP_API(void*) LDAP_CALL ber_special_alloc(size_t size, BerElement **ppBer);
+LDAP_API(BerElement*) LDAP_CALL ber_dup( BerElement *ber );
+LDAP_API(ber_tag_t) LDAP_CALL ber_get_next( Sockbuf *sb, ber_len_t *len,
+	BerElement *ber );
+LDAP_API(ber_tag_t) LDAP_CALL ber_get_next_buffer( void *buffer,
+	size_t buffer_size, ber_len_t *len, BerElement *ber,
+	ber_len_t *Bytes_Scanned );
+LDAP_API(ber_tag_t) LDAP_CALL ber_get_next_buffer_ext( void *buffer,
+	size_t buffer_size, ber_len_t *len, BerElement *ber,
+	ber_len_t *Bytes_Scanned, Sockbuf *sb );
+LDAP_API(ber_int_t) LDAP_CALL ber_read( BerElement *ber, char *buf, 
+	ber_len_t len );
+LDAP_API(ber_int_t) LDAP_CALL ber_write( BerElement *ber, char *buf, 
+	ber_len_t len, int nosos );
+LDAP_API(void) LDAP_CALL ber_init_w_nullchar( BerElement *ber, int options );
+LDAP_API(void) LDAP_CALL ber_reset( BerElement *ber, int was_writing );
+LDAP_API(size_t) LDAP_CALL ber_get_buf_datalen( BerElement *ber );
+LDAP_API(int) LDAP_CALL ber_stack_init(BerElement *ber, int options, 
+	char * buf, size_t size);
+LDAP_API(char*) LDAP_CALL ber_get_buf_databegin (BerElement * ber);
+LDAP_API(void) LDAP_CALL ber_sockbuf_free_data(Sockbuf *p);
+LDAP_API(int) LDAP_CALL ber_set_option( BerElement *ber, int option, 
+	void *value );
+LDAP_API(int) LDAP_CALL ber_get_option( BerElement *ber, int option, 
+	void *value );
+LDAP_API(Sockbuf*) LDAP_CALL ber_sockbuf_alloc( void );
+LDAP_API(void) LDAP_CALL ber_sockbuf_free( Sockbuf* p );
+LDAP_API(int) LDAP_CALL ber_sockbuf_set_option( Sockbuf *sb, int option, 
+	void *value );
+LDAP_API(int) LDAP_CALL ber_sockbuf_get_option( Sockbuf *sb, int option, 
+	void *value );
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _LBER_H */
+
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/include/lcache.h
@@ -0,0 +1,94 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+/* lcache.h - ldap persistent cache */
+#ifndef _LCACHE_H
+#define _LCACHE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* calling conventions used by library */
+#ifndef LDAP_CALL
+#if defined( _WINDOWS ) || defined( _WIN32 )
+#define LDAP_C __cdecl
+#ifndef _WIN32 
+#define __stdcall _far _pascal
+#define LDAP_CALLBACK _loadds
+#else
+#define LDAP_CALLBACK
+#endif /* _WIN32 */
+#define LDAP_PASCAL __stdcall
+#define LDAP_CALL LDAP_PASCAL
+#else /* _WINDOWS */
+#define LDAP_C
+#define LDAP_CALLBACK
+#define LDAP_PASCAL
+#define LDAP_CALL
+#endif /* _WINDOWS */
+#endif /* LDAP_CALL */
+
+LDAP_API(int) LDAP_C lcache_init( LDAP *ld, void *arg );
+LDAP_API(int) LDAP_C lcache_bind( LDAP *ld, int msgid, unsigned long tag,
+	const char *dn, struct berval *cred, int method );
+LDAP_API(int) LDAP_C lcache_unbind( LDAP *ld, int msgid, unsigned long tag );
+LDAP_API(int) LDAP_C lcache_search( LDAP *ld, int msgid, unsigned long tag,
+	const char *dn, int scope, const char *filter, char **attrs,
+	int attrsonly );
+LDAP_API(int) LDAP_C lcache_compare( LDAP *ld, int msgid, unsigned long tag,
+	const char *dn, const char *attr, struct berval *val );
+LDAP_API(int) LDAP_C lcache_add( LDAP *ld, int msgid, unsigned long tag,
+	const char *dn, LDAPMod **entry );
+LDAP_API(int) LDAP_C lcache_delete( LDAP *ld, int msgid, unsigned long tag,
+	const char *dn );
+LDAP_API(int) LDAP_C lcache_rename( LDAP *ld, int msgid, unsigned long tag,
+	const char *dn, const char *newrdn, const char *newparent, 
+	int deleteoldrdn );
+LDAP_API(int) LDAP_C lcache_modify( LDAP *ld, int msgid, unsigned long tag,
+	const char *dn, LDAPMod **mods );
+LDAP_API(int) LDAP_C lcache_modrdn( LDAP *ld, int msgid, unsigned long tag,
+	const char *dn, const char *newrdn, int deleteoldrdn );
+LDAP_API(int) LDAP_C lcache_result( LDAP *ld, int msgid, int all,
+	struct timeval *timeout, LDAPMessage **result );
+LDAP_API(int) LDAP_C lcache_flush( LDAP *ld, char *dn, char *filter );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LCACHE_H */
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/include/ldap-deprecated.h
@@ -0,0 +1,201 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+/* ldap-deprecated.h - deprecated functions and declarations
+ *
+ * A deprecated API is an API that we recommend you no longer use,
+ * due to improvements in the LDAP C SDK. While deprecated APIs are
+ * currently still implemented, they may be removed in future
+ * implementations, and we recommend using other APIs.
+ *
+ * This file contain functions and declarations which have
+ * outlived their usefullness and have been deprecated.  In many
+ * cases functions and declarations have been replaced with newer
+ * extended functions.  In no way should applications rely on the
+ * declarations and defines within this files as they can and will
+ * disappear without any notice.
+ */
+
+#ifndef _LDAP_DEPRECATED_H
+#define _LDAP_DEPRECATED_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * establish an ldap session
+ */
+LDAP_API(LDAP *) LDAP_CALL ldap_open( const char *host, int port );
+
+/*
+ * Authentication methods:
+ */
+#define LDAP_AUTH_NONE          0x00L
+#define LDAP_AUTH_SIMPLE        0x80L
+#define LDAP_AUTH_SASL          0xa3L
+LDAP_API(int) LDAP_CALL ldap_bind( LDAP *ld, const char *who,
+        const char *passwd, int authmethod );
+LDAP_API(int) LDAP_CALL ldap_bind_s( LDAP *ld, const char *who,
+        const char *cred, int method );
+
+LDAP_API(int) LDAP_CALL ldap_modrdn( LDAP *ld, const char *dn,
+        const char *newrdn );
+LDAP_API(int) LDAP_CALL ldap_modrdn_s( LDAP *ld, const char *dn,
+        const char *newrdn );
+LDAP_API(int) LDAP_CALL ldap_modrdn2( LDAP *ld, const char *dn,
+        const char *newrdn, int deleteoldrdn );
+LDAP_API(int) LDAP_CALL ldap_modrdn2_s( LDAP *ld, const char *dn,
+        const char *newrdn, int deleteoldrdn);
+
+LDAP_API(void) LDAP_CALL ldap_perror( LDAP *ld, const char *s );
+LDAP_API(int) LDAP_CALL ldap_result2error( LDAP *ld, LDAPMessage *r,
+        int freeit );
+
+/*
+ * Preferred language and get_lang_values (an API extension --
+ * LDAP_API_FEATURE_X_GETLANGVALUES)
+ *
+ * The following two APIs are deprecated
+ */
+
+#define LDAP_OPT_PREFERRED_LANGUAGE     0x14    /* 20 - API extension */
+LDAP_API(char **) LDAP_CALL ldap_get_lang_values( LDAP *ld, LDAPMessage *entry,
+        const char *target, char **type );
+LDAP_API(struct berval **) LDAP_CALL ldap_get_lang_values_len( LDAP *ld,
+        LDAPMessage *entry, const char *target, char **type );
+
+/*
+ * Asynchronous I/O (an API extension).
+ */
+/*
+ * This option enables completely asynchronous IO.  It works by using ioctl()
+ * on the fd, (or tlook())
+ */
+#define LDAP_OPT_ASYNC_CONNECT          0x63    /* 99 - API extension */
+
+/*
+ * functions and definitions that have been replaced by new improved ones
+ */
+/*
+ * Use ldap_get_option() with LDAP_OPT_API_INFO and an LDAPAPIInfo structure
+ * instead of ldap_version().
+ */
+typedef struct _LDAPVersion {
+        int sdk_version;      /* Version of the SDK, * 100 */
+        int protocol_version; /* Highest protocol version supported, * 100 */
+        int SSL_version;      /* SSL version if this SDK supports it, * 100 */
+        int security_level;   /* highest level available */
+        int reserved[4];
+} LDAPVersion;
+#define LDAP_SECURITY_NONE      0
+LDAP_API(int) LDAP_CALL ldap_version( LDAPVersion *ver );
+
+/* use ldap_create_filter() instead of ldap_build_filter() */
+LDAP_API(void) LDAP_CALL ldap_build_filter( char *buf, unsigned long buflen,
+        char *pattern, char *prefix, char *suffix, char *attr,
+        char *value, char **valwords );
+/* use ldap_set_filter_additions() instead of ldap_setfilteraffixes() */
+LDAP_API(void) LDAP_CALL ldap_setfilteraffixes( LDAPFiltDesc *lfdp,
+        char *prefix, char *suffix );
+
+/* older result types a server can return -- use LDAP_RES_MODDN instead */
+#define LDAP_RES_MODRDN                 LDAP_RES_MODDN
+#define LDAP_RES_RENAME                 LDAP_RES_MODDN
+
+/* older error messages */
+#define LDAP_AUTH_METHOD_NOT_SUPPORTED  LDAP_STRONG_AUTH_NOT_SUPPORTED
+
+/*
+ * Generalized cache callback interface:
+ */
+#define LDAP_OPT_CACHE_FN_PTRS          0x0D    /* 13 - API extension */
+#define LDAP_OPT_CACHE_STRATEGY         0x0E    /* 14 - API extension */
+#define LDAP_OPT_CACHE_ENABLE           0x0F    /* 15 - API extension */
+
+/* cache strategies */
+#define LDAP_CACHE_CHECK                0
+#define LDAP_CACHE_POPULATE             1
+#define LDAP_CACHE_LOCALDB              2
+
+typedef int (LDAP_C LDAP_CALLBACK LDAP_CF_BIND_CALLBACK)( LDAP *ld, int msgid,
+        unsigned long tag, const char *dn, const struct berval *creds,
+        int method);
+typedef int (LDAP_C LDAP_CALLBACK LDAP_CF_UNBIND_CALLBACK)( LDAP *ld,
+        int unused0, unsigned long unused1 );
+typedef int (LDAP_C LDAP_CALLBACK LDAP_CF_SEARCH_CALLBACK)( LDAP *ld,
+        int msgid, unsigned long tag, const char *base, int scope,
+        const char LDAP_CALLBACK *filter, char **attrs, int attrsonly );
+typedef int (LDAP_C LDAP_CALLBACK LDAP_CF_COMPARE_CALLBACK)( LDAP *ld,
+        int msgid, unsigned long tag, const char *dn, const char *attr,
+        const struct berval *value );
+typedef int (LDAP_C LDAP_CALLBACK LDAP_CF_ADD_CALLBACK)( LDAP *ld,
+        int msgid, unsigned long tag, const char *dn, LDAPMod **attrs );
+typedef int (LDAP_C LDAP_CALLBACK LDAP_CF_DELETE_CALLBACK)( LDAP *ld,
+        int msgid, unsigned long tag, const char *dn );
+typedef int (LDAP_C LDAP_CALLBACK LDAP_CF_MODIFY_CALLBACK)( LDAP *ld,
+        int msgid, unsigned long tag, const char *dn, LDAPMod **mods );
+typedef int (LDAP_C LDAP_CALLBACK LDAP_CF_MODRDN_CALLBACK)( LDAP *ld,
+        int msgid, unsigned long tag, const char *dn, const char *newrdn,
+        int deleteoldrdn );
+typedef int (LDAP_C LDAP_CALLBACK LDAP_CF_RESULT_CALLBACK)( LDAP *ld,
+        int msgid, int all, struct timeval *timeout, LDAPMessage **result );
+typedef int (LDAP_C LDAP_CALLBACK LDAP_CF_FLUSH_CALLBACK)( LDAP *ld,
+        const char *dn, const char *filter );
+
+struct ldap_cache_fns {
+        void    *lcf_private;
+        LDAP_CF_BIND_CALLBACK *lcf_bind;
+        LDAP_CF_UNBIND_CALLBACK *lcf_unbind;
+        LDAP_CF_SEARCH_CALLBACK *lcf_search;
+        LDAP_CF_COMPARE_CALLBACK *lcf_compare;
+        LDAP_CF_ADD_CALLBACK *lcf_add;
+        LDAP_CF_DELETE_CALLBACK *lcf_delete;
+        LDAP_CF_MODIFY_CALLBACK *lcf_modify;
+        LDAP_CF_MODRDN_CALLBACK *lcf_modrdn;
+        LDAP_CF_RESULT_CALLBACK *lcf_result;
+        LDAP_CF_FLUSH_CALLBACK *lcf_flush;
+};
+
+LDAP_API(int) LDAP_CALL ldap_cache_flush( LDAP *ld, const char *dn,
+        const char *filter );
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _LDAP_DEPRECATED_H */
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/include/ldap-extension.h
@@ -0,0 +1,853 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+/* ldap-extension.h - extensions to the ldap c api specification */
+
+#ifndef _LDAP_EXTENSION_H
+#define _LDAP_EXTENSION_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LDAP_PORT_MAX           65535           /* API extension */
+#define LDAP_VERSION1           1               /* API extension */
+#define LDAP_VERSION            LDAP_VERSION3   /* API extension */
+
+/*
+ * C LDAP features we support that are not (yet) part of the LDAP C API
+ * Internet Draft.  Use the ldap_get_option() call with an option value of
+ * LDAP_OPT_API_FEATURE_INFO to retrieve information about a feature.
+ *
+ * Note that this list is incomplete; it includes only the most widely
+ * used extensions.  Also, the version is 1 for all of these for now.
+ */
+#define LDAP_API_FEATURE_SERVER_SIDE_SORT       1
+#define LDAP_API_FEATURE_VIRTUAL_LIST_VIEW      1
+#define LDAP_API_FEATURE_PERSISTENT_SEARCH      1
+#define LDAP_API_FEATURE_PROXY_AUTHORIZATION    1
+#define LDAP_API_FEATURE_X_LDERRNO              1
+#define LDAP_API_FEATURE_X_MEMCACHE             1
+#define LDAP_API_FEATURE_X_IO_FUNCTIONS         1
+#define LDAP_API_FEATURE_X_EXTIO_FUNCTIONS      1
+#define LDAP_API_FEATURE_X_DNS_FUNCTIONS        1
+#define LDAP_API_FEATURE_X_MEMALLOC_FUNCTIONS   1
+#define LDAP_API_FEATURE_X_THREAD_FUNCTIONS     1
+#define LDAP_API_FEATURE_X_EXTHREAD_FUNCTIONS   1
+#define LDAP_API_FEATURE_X_GETLANGVALUES        1
+#define LDAP_API_FEATURE_X_CLIENT_SIDE_SORT     1
+#define LDAP_API_FEATURE_X_URL_FUNCTIONS        1
+#define LDAP_API_FEATURE_X_FILTER_FUNCTIONS     1
+
+#define LDAP_ROOT_DSE           ""              /* API extension */
+
+#define LDAP_OPT_DESC                   0x01    /*  1 */
+
+#define NULLMSG ((LDAPMessage *)0)
+
+/*built-in SASL methods */
+#define LDAP_SASL_EXTERNAL      "EXTERNAL"      /* TLS/SSL extension */
+
+/* possible error codes we can be returned */
+#define LDAP_PARTIAL_RESULTS            0x09    /* 9 (UMich LDAPv2 extn) */
+#define NAME_ERROR(n)   ((n & 0xf0) == 0x20)
+
+#define LDAP_SORT_CONTROL_MISSING       0x3C    /* 60 (server side sort extn) */
+#define LDAP_INDEX_RANGE_ERROR          0x3D    /* 61 (VLV extn) */
+
+/*
+ * LDAPv3 server controls we know about
+ */
+#define LDAP_CONTROL_MANAGEDSAIT        "2.16.840.1.113730.3.4.2"
+#define LDAP_CONTROL_SORTREQUEST        "1.2.840.113556.1.4.473"
+#define LDAP_CONTROL_SORTRESPONSE       "1.2.840.113556.1.4.474"
+#define LDAP_CONTROL_PERSISTENTSEARCH   "2.16.840.1.113730.3.4.3"
+#define LDAP_CONTROL_ENTRYCHANGE        "2.16.840.1.113730.3.4.7"
+#define LDAP_CONTROL_VLVREQUEST         "2.16.840.1.113730.3.4.9"
+#define LDAP_CONTROL_VLVRESPONSE        "2.16.840.1.113730.3.4.10"
+#define LDAP_CONTROL_PROXYAUTH          "2.16.840.1.113730.3.4.12" /* version 1
+*/
+#define LDAP_CONTROL_PROXIEDAUTH        "2.16.840.1.113730.3.4.18" /* version 2
+*/
+
+/* Authorization Identity Request and Response Controls */
+#define LDAP_CONTROL_AUTHZID_REQ        "2.16.840.1.113730.3.4.16"
+#define LDAP_CONTROL_AUTHZID_RES        "2.16.840.1.113730.3.4.15"
+
+/* Authentication request and response controls */
+#define LDAP_CONTROL_AUTH_REQUEST       LDAP_CONTROL_AUTHZID_REQ
+#define LDAP_CONTROL_AUTH_RESPONSE      LDAP_CONTROL_AUTHZID_RES
+
+/* Password information sent back to client */
+#define LDAP_CONTROL_PWEXPIRED          "2.16.840.1.113730.3.4.4"
+#define LDAP_CONTROL_PWEXPIRING         "2.16.840.1.113730.3.4.5"
+
+/* Password Policy Control */
+#define LDAP_CONTROL_PASSWD_POLICY      "1.3.6.1.4.1.42.2.27.8.5.1"
+
+/* Password Policy Control compatibility macros */
+#define LDAP_X_CONTROL_PWPOLICY_REQUEST		LDAP_CONTROL_PASSWD_POLICY
+#define LDAP_X_CONTROL_PWPOLICY_RESPONSE	LDAP_CONTROL_PASSWD_POLICY
+#define LDAP_CONTROL_PASSWORDPOLICYREQUEST	LDAP_CONTROL_PASSWD_POLICY
+#define LDAP_CONTROL_PASSWORDPOLICYRESPONSE	LDAP_CONTROL_PASSWD_POLICY
+
+/* Password Modify Extended Operation */
+#define LDAP_EXOP_MODIFY_PASSWD			"1.3.6.1.4.1.4203.1.11.1"
+
+/* Suppress virtual/inherited attribute values */
+#define LDAP_CONTROL_REAL_ATTRS_ONLY	"2.16.840.1.113730.3.4.17"
+
+/* Only return virtual/inherited attribute values */
+#define LDAP_CONTROL_VIRTUAL_ATTRS_ONLY	"2.16.840.1.113730.3.4.19"
+
+/* getEffectiveRights request */
+#define LDAP_CONTROL_GETEFFECTIVERIGHTS_REQUEST "1.3.6.1.4.1.42.2.27.9.5.2"
+
+/* Password Policy Control to get account availability */	
+#define LDAP_CONTROL_ACCOUNT_USABLE     "1.3.6.1.4.1.42.2.27.9.5.8"
+
+/* "Who am I?" Extended Operation */	
+#define LDAP_EXOP_WHO_AM_I				"1.3.6.1.4.1.4203.1.11.3"
+
+LDAP_API(void) LDAP_CALL ldap_ber_free( BerElement *ber, int freebuf );
+
+LDAP_API(LDAPControl *) LDAP_CALL ldap_find_control( const char *oid, 
+		LDAPControl **ctrls );
+
+/*
+ * Server side sorting of search results (an LDAPv3 extension --
+ * LDAP_API_FEATURE_SERVER_SIDE_SORT)
+ */
+typedef struct LDAPsortkey {    /* structure for a sort-key */
+        char *  sk_attrtype;
+        char *  sk_matchruleoid;
+        int     sk_reverseorder;
+} LDAPsortkey;
+
+/* where LDAP_CONTROL_ACCOUNT_USABLE control parse results */
+typedef struct LDAPuserstatus {     /* user account availability   */
+        unsigned int us_available;  /* availability status         */
+#define LDAP_US_ACCOUNT_USABLE      1
+#define LDAP_US_ACCOUNT_NOT_USABLE  0
+        int          us_expire;     /* will expire in seconds      */
+        int          us_inactive;   /* boolean inactivation status */
+#define LDAP_US_ACCOUNT_ACTIVE      0
+#define LDAP_US_ACCOUNT_INACTIVE    1
+        int          us_reset;      /* boolean password reset      */
+#define LDAP_US_ACCOUNT_NOT_RESET   0
+#define LDAP_US_ACCOUNT_RESET       1
+        int          us_expired;    /* boolean password expired    */
+#define LDAP_US_ACCOUNT_NOT_EXPIRED 0
+#define LDAP_US_ACCOUNT_EXPIRED     1
+        int          us_remaining;  /* remaining logins            */
+        int          us_seconds;    /* will unlock in seconds      */
+} LDAPuserstatus;
+
+/* LDAP_CONTROL_PASSWD_POLICY results */
+typedef enum passpolicyerror_enum {
+       PP_passwordExpired = 0,
+       PP_accountLocked = 1,
+       PP_changeAfterReset = 2,
+       PP_passwordModNotAllowed = 3,
+       PP_mustSupplyOldPassword = 4,
+       PP_insufficientPasswordQuality = 5,
+       PP_passwordTooShort = 6,
+       PP_passwordTooYoung = 7,
+       PP_passwordInHistory = 8,
+       PP_noError = 65535
+} LDAPPasswordPolicyError;
+
+LDAP_API(int) LDAP_CALL ldap_create_sort_control( LDAP *ld,
+        LDAPsortkey **sortKeyList, const char ctl_iscritical,
+        LDAPControl **ctrlp );
+LDAP_API(int) LDAP_CALL ldap_parse_sort_control( LDAP *ld,
+        LDAPControl **ctrls, ber_int_t *result, char **attribute );
+
+LDAP_API(void) LDAP_CALL ldap_free_sort_keylist( LDAPsortkey **sortKeyList );
+LDAP_API(int) LDAP_CALL ldap_create_sort_keylist( LDAPsortkey ***sortKeyList,
+        const char *string_rep );
+
+LDAP_API(int) LDAP_CALL ldap_create_userstatus_control( 
+		LDAP *ld, const char ctl_iscritical, LDAPControl **ctrlp );
+LDAP_API(int) LDAP_CALL ldap_parse_userstatus_control( LDAP *ld, 
+		LDAPControl **ctrlp, LDAPuserstatus *us );
+
+LDAP_API(int) LDAP_CALL ldap_create_passwordpolicy_control( LDAP *ld, 
+		LDAPControl **ctrlp );
+LDAP_API(int) LDAP_CALL ldap_create_passwordpolicy_control_ext( LDAP *ld, 
+		const char ctl_iscritical, LDAPControl **ctrlp );
+LDAP_API(int) LDAP_CALL ldap_parse_passwordpolicy_control( LDAP *ld, 
+		LDAPControl *ctrlp, ber_int_t *expirep, ber_int_t *gracep,
+		LDAPPasswordPolicyError *errorp );
+LDAP_API(int) LDAP_CALL ldap_parse_passwordpolicy_control_ext ( LDAP *ld, 
+		LDAPControl **ctrlp, ber_int_t *expirep, ber_int_t *gracep,
+		LDAPPasswordPolicyError *errorp );
+LDAP_API(const char *) LDAP_CALL ldap_passwordpolicy_err2txt( 
+		LDAPPasswordPolicyError err );
+
+LDAP_API(int) LDAP_CALL ldap_create_authzid_control( LDAP *ld, 
+		const char ctl_iscritical, LDAPControl **ctrlp );
+LDAP_API(int) LDAP_CALL ldap_parse_authzid_control( LDAP *ld, 
+		LDAPControl **ctrlp, char **authzid );
+
+LDAP_API(int) LDAP_CALL ldap_whoami( LDAP *ld, LDAPControl **serverctrls, 
+		LDAPControl **clientctrls, int *msgidp );
+LDAP_API(int) LDAP_CALL ldap_whoami_s( LDAP *ld, struct berval **authzid,
+		LDAPControl **serverctrls, LDAPControl **clientctrls );
+LDAP_API(int) LDAP_CALL ldap_parse_whoami( LDAP *ld, LDAPMessage *result, 
+		struct berval **authzid );
+
+LDAP_API(int) LDAP_CALL ldap_create_geteffectiveRights_control( LDAP *ld,
+        const char *authzid, const char **attrlist,  const char ctl_iscritical,
+		LDAPControl **ctrlp );
+
+/*
+ * Virtual list view (an LDAPv3 extension -- LDAP_API_FEATURE_VIRTUAL_LIST_VIEW)
+ */
+/*
+ * structure that describes a VirtualListViewRequest control.
+ * note that ldvlist_index and ldvlist_size are only relevant to
+ * ldap_create_virtuallist_control() if ldvlist_attrvalue is NULL.
+ */
+typedef struct ldapvirtuallist {
+    ber_int_t   ldvlist_before_count;       /* # entries before target */
+    ber_int_t   ldvlist_after_count;        /* # entries after target */
+    char        *ldvlist_attrvalue;         /* jump to this value */
+    ber_int_t   ldvlist_index;              /* list offset */
+    ber_int_t   ldvlist_size;               /* number of items in vlist */
+    void        *ldvlist_extradata;         /* for use by application */
+} LDAPVirtualList;
+
+/*
+ * VLV functions:
+ */
+LDAP_API(int) LDAP_CALL ldap_create_virtuallist_control( LDAP *ld,
+        LDAPVirtualList *ldvlistp, LDAPControl **ctrlp );
+
+LDAP_API(int) LDAP_CALL ldap_parse_virtuallist_control( LDAP *ld,
+        LDAPControl **ctrls, ber_int_t *target_posp,
+        ber_int_t *list_sizep, int *errcodep );
+
+/*
+ * Routines for creating persistent search controls and for handling
+ * "entry changed notification" controls (an LDAPv3 extension --
+ * LDAP_API_FEATURE_PERSISTENT_SEARCH)
+ */
+#define LDAP_CHANGETYPE_ADD             1
+#define LDAP_CHANGETYPE_DELETE          2
+#define LDAP_CHANGETYPE_MODIFY          4
+#define LDAP_CHANGETYPE_MODDN           8
+#define LDAP_CHANGETYPE_ANY             (1|2|4|8)
+LDAP_API(int) LDAP_CALL ldap_create_persistentsearch_control( LDAP *ld,
+        int changetypes, int changesonly, int return_echg_ctls,
+        char ctl_iscritical, LDAPControl **ctrlp );
+LDAP_API(int) LDAP_CALL ldap_parse_entrychange_control( LDAP *ld,
+        LDAPControl **ctrls, ber_int_t *chgtypep, char **prevdnp,
+        int *chgnumpresentp, ber_int_t *chgnump );
+
+/*
+ * Routines for creating Proxied Authorization controls (an LDAPv3
+ * extension -- LDAP_API_FEATURE_PROXY_AUTHORIZATION)
+ * ldap_create_proxyauth_control() is for the old (version 1) control.
+ * ldap_create_proxiedauth_control() is for the newer (version 2) control.
+ */
+LDAP_API(int) LDAP_CALL ldap_create_proxyauth_control( LDAP *ld,
+        const char *dn, const char ctl_iscritical, LDAPControl **ctrlp );
+LDAP_API(int) LDAP_CALL ldap_create_proxiedauth_control( LDAP *ld,
+        const char *authzid, LDAPControl **ctrlp );
+
+/*
+ * Functions to get and set LDAP error information (API extension --
+ * LDAP_API_FEATURE_X_LDERRNO )
+ *
+ * By using LDAP_OPT_THREAD_FN_PTRS, you can arrange for the error info. to
+ * be thread-specific.
+ */
+LDAP_API(int) LDAP_CALL ldap_get_lderrno( LDAP *ld, char **m, char **s );
+LDAP_API(int) LDAP_CALL ldap_set_lderrno( LDAP *ld, int e, char *m, char *s );
+
+
+/*
+ * LDAP URL functions and definitions (an API extension --
+ * LDAP_API_FEATURE_X_URL_FUNCTIONS)
+ */
+/*
+ * types for ldap URL handling
+ */
+typedef struct ldap_url_desc {
+    char                *lud_host;
+    int                 lud_port;
+    char                *lud_dn;
+    char                **lud_attrs;
+    int                 lud_scope;
+    char                *lud_filter;
+    unsigned long       lud_options;
+#define LDAP_URL_OPT_SECURE     0x01
+    char        *lud_string;    /* for internal use only */
+} LDAPURLDesc;
+
+#define NULLLDAPURLDESC ((LDAPURLDesc *)NULL)
+
+/*
+ * possible errors returned by ldap_url_parse()
+ */
+#define LDAP_URL_ERR_NOTLDAP    1       /* URL doesn't begin with "ldap://" */
+#define LDAP_URL_ERR_NODN       2       /* URL has no DN (required) */
+#define LDAP_URL_ERR_BADSCOPE   3       /* URL scope string is invalid */
+#define LDAP_URL_ERR_MEM        4       /* can't allocate memory space */
+#define LDAP_URL_ERR_PARAM      5       /* bad parameter to an URL function */
+#define LDAP_URL_UNRECOGNIZED_CRITICAL_EXTENSION	6
+
+/*
+ * URL functions:
+ */
+LDAP_API(int) LDAP_CALL ldap_is_ldap_url( const char *url );
+LDAP_API(int) LDAP_CALL ldap_url_parse( const char *url, LDAPURLDesc **ludpp );
+LDAP_API(int) LDAP_CALL ldap_url_parse_no_defaults( const char *url, 
+        LDAPURLDesc **ludpp, int dn_required);
+LDAP_API(void) LDAP_CALL ldap_free_urldesc( LDAPURLDesc *ludp );
+LDAP_API(int) LDAP_CALL ldap_url_search( LDAP *ld, const char *url,
+        int attrsonly );
+LDAP_API(int) LDAP_CALL ldap_url_search_s( LDAP *ld, const char *url,
+        int attrsonly, LDAPMessage **res );
+LDAP_API(int) LDAP_CALL ldap_url_search_st( LDAP *ld, const char *url,
+        int attrsonly, struct timeval *timeout, LDAPMessage **res );
+
+
+/*
+ * Function to dispose of an array of LDAPMod structures (an API extension).
+ * Warning: don't use this unless the mods array was allocated using the
+ * same memory allocator as is being used by libldap.
+ */
+LDAP_API(void) LDAP_CALL ldap_mods_free( LDAPMod **mods, int freemods );
+
+/*
+ * SSL option (an API extension):
+ */
+#define LDAP_OPT_SSL                    0x0A    /* 10 - API extension */
+
+/*
+ * Referral hop limit (an API extension):
+ */
+#define LDAP_OPT_REFERRAL_HOP_LIMIT     0x10    /* 16 - API extension */
+
+/*
+ * Rebind callback function (an API extension)
+ */
+#define LDAP_OPT_REBIND_FN              0x06    /* 6 - API extension */
+#define LDAP_OPT_REBIND_ARG             0x07    /* 7 - API extension */
+typedef int (LDAP_CALL LDAP_CALLBACK LDAP_REBINDPROC_CALLBACK)( LDAP *ld,
+        char **dnp, char **passwdp, int *authmethodp, int freeit, void *arg);
+LDAP_API(void) LDAP_CALL ldap_set_rebind_proc( LDAP *ld,
+        LDAP_REBINDPROC_CALLBACK *rebindproc, void *arg );
+
+/*
+ * Thread function callbacks (an API extension --
+ * LDAP_API_FEATURE_X_THREAD_FUNCTIONS).
+ */
+#define LDAP_OPT_THREAD_FN_PTRS         0x05    /* 5 - API extension */
+
+/*
+ * Thread callback functions:
+ */
+typedef void *(LDAP_C LDAP_CALLBACK LDAP_TF_MUTEX_ALLOC_CALLBACK)( void );
+typedef void (LDAP_C LDAP_CALLBACK LDAP_TF_MUTEX_FREE_CALLBACK)( void *m );
+typedef int (LDAP_C LDAP_CALLBACK LDAP_TF_MUTEX_LOCK_CALLBACK)( void *m );
+typedef int (LDAP_C LDAP_CALLBACK LDAP_TF_MUTEX_UNLOCK_CALLBACK)( void *m );
+typedef int (LDAP_C LDAP_CALLBACK LDAP_TF_GET_ERRNO_CALLBACK)( void );
+typedef void (LDAP_C LDAP_CALLBACK LDAP_TF_SET_ERRNO_CALLBACK)( int e );
+typedef int (LDAP_C LDAP_CALLBACK LDAP_TF_GET_LDERRNO_CALLBACK)(
+        char **matchedp, char **errmsgp, void *arg );
+typedef void    (LDAP_C LDAP_CALLBACK LDAP_TF_SET_LDERRNO_CALLBACK)( int err,
+        char *matched, char *errmsg, void *arg );
+
+/*
+ * Structure to hold thread function pointers:
+ */
+struct ldap_thread_fns {
+        LDAP_TF_MUTEX_ALLOC_CALLBACK *ltf_mutex_alloc;
+        LDAP_TF_MUTEX_FREE_CALLBACK *ltf_mutex_free;
+        LDAP_TF_MUTEX_LOCK_CALLBACK *ltf_mutex_lock;
+        LDAP_TF_MUTEX_UNLOCK_CALLBACK *ltf_mutex_unlock;
+        LDAP_TF_GET_ERRNO_CALLBACK *ltf_get_errno;
+        LDAP_TF_SET_ERRNO_CALLBACK *ltf_set_errno;
+        LDAP_TF_GET_LDERRNO_CALLBACK *ltf_get_lderrno;
+        LDAP_TF_SET_LDERRNO_CALLBACK *ltf_set_lderrno;
+        void    *ltf_lderrno_arg;
+};
+
+/*
+ * Extended I/O function callbacks option (an API extension --
+ * LDAP_API_FEATURE_X_EXTIO_FUNCTIONS).
+ */
+#define LDAP_X_OPT_EXTIO_FN_PTRS   (LDAP_OPT_PRIVATE_EXTENSION_BASE + 0x0F00)
+        /* 0x4000 + 0x0F00 = 0x4F00 = 20224 - API extension */
+
+/* Additional Extended I/O function callback option (for Extended Socket Arg callback) */
+#define LDAP_X_OPT_SOCKETARG	(LDAP_OPT_PRIVATE_EXTENSION_BASE + 0x0F02)
+        /* 0x4000 + 0x0F02 = 0x4F02 = 20226 - API extension */
+	
+/*
+ * These extended I/O function callbacks echo the BSD socket API but accept
+ * an extra pointer parameter at the end of their argument list that can
+ * be used by client applications for their own needs.  For some of the calls,
+ * the pointer is a session argument of type struct lextiof_session_private *
+ * that is associated with the LDAP session handle (LDAP *).  For others, the
+ * pointer is a socket specific struct lextiof_socket_private * argument that
+ * is associated with a particular socket (a TCP connection).
+ *
+ * The lextiof_session_private and lextiof_socket_private structures are not
+ * defined by the LDAP C API; users of this extended I/O interface should
+ * define these themselves.
+ *
+ * The combination of the integer socket number (i.e., lpoll_fd, which is
+ * the value returned by the CONNECT callback) and the application specific
+ * socket argument (i.e., lpoll_socketarg, which is the value set in *sockargpp
+ * by the CONNECT callback) must be unique.
+ *
+ * The types for the extended READ and WRITE callbacks are actually in lber.h.
+ *
+ * The CONNECT callback gets passed both the session argument (sessionarg)
+ * and a pointer to a socket argument (socketargp) so it has the
+ * opportunity to set the socket-specific argument.  The CONNECT callback
+ * also takes a timeout parameter whose value can be set by calling
+ * ldap_set_option( ld, LDAP_X_OPT_..., &val ).  The units used for the
+ * timeout parameter are milliseconds.
+ *
+ * A POLL interface is provided instead of a select() one.  The timeout is
+ * in milliseconds.
+ *
+ * A NEWHANDLE callback function is also provided.  It is called right
+ * after the LDAP session handle is created, e.g., during ldap_init().
+ * If the NEWHANDLE callback returns anything other than LDAP_SUCCESS,
+ * the session handle allocation fails.
+ *
+ * A DISPOSEHANDLE callback function is also provided.  It is called right
+ * before the LDAP session handle and its contents are destroyed, e.g.,
+ * during ldap_unbind().
+ */
+
+/*
+ * Special timeout values for poll and connect:
+ */
+#define LDAP_X_IO_TIMEOUT_NO_WAIT       0       /* return immediately */
+#define LDAP_X_IO_TIMEOUT_NO_TIMEOUT    (-1)    /* block indefinitely */
+
+/* LDAP poll()-like descriptor:
+ */
+typedef struct ldap_x_pollfd {     /* used by LDAP_X_EXTIOF_POLL_CALLBACK */
+    int         lpoll_fd;          /* integer file descriptor / socket */
+    struct lextiof_socket_private
+                *lpoll_socketarg;
+                                   /* pointer socket and for use by */
+                                   /* application */
+    short       lpoll_events;      /* requested event */
+    short       lpoll_revents;     /* returned event */
+} LDAP_X_PollFD;
+
+/* Event flags for lpoll_events and lpoll_revents:
+ */
+#define LDAP_X_POLLIN    0x01  /* regular data ready for reading */
+#define LDAP_X_POLLPRI   0x02  /* high priority data available */
+#define LDAP_X_POLLOUT   0x04  /* ready for writing */
+#define LDAP_X_POLLERR   0x08  /* error occurred -- only in lpoll_revents */
+#define LDAP_X_POLLHUP   0x10  /* connection closed -- only in lpoll_revents */
+#define LDAP_X_POLLNVAL  0x20  /* invalid lpoll_fd -- only in lpoll_revents */
+
+/* Options passed to LDAP_X_EXTIOF_CONNECT_CALLBACK to modify socket behavior:
+ */
+#define LDAP_X_EXTIOF_OPT_NONBLOCKING   0x01  /* turn on non-blocking mode */
+#define LDAP_X_EXTIOF_OPT_SECURE        0x02  /* turn on 'secure' mode */
+
+
+/* extended I/O callback function prototypes:
+ */
+typedef int     (LDAP_C LDAP_CALLBACK LDAP_X_EXTIOF_CONNECT_CALLBACK )(
+            const char *hostlist, int port, /* host byte order */
+            int timeout /* milliseconds */,
+            unsigned long options, /* bitmapped options */
+            struct lextiof_session_private *sessionarg,
+            struct lextiof_socket_private **socketargp );
+typedef int     (LDAP_C LDAP_CALLBACK LDAP_X_EXTIOF_CLOSE_CALLBACK )(
+            int s, struct lextiof_socket_private *socketarg );
+typedef int     (LDAP_C LDAP_CALLBACK LDAP_X_EXTIOF_POLL_CALLBACK)(
+            LDAP_X_PollFD fds[], int nfds, int timeout /* milliseconds */,
+            struct lextiof_session_private *sessionarg );
+typedef int     (LDAP_C LDAP_CALLBACK LDAP_X_EXTIOF_NEWHANDLE_CALLBACK)(
+            LDAP *ld, struct lextiof_session_private *sessionarg );
+typedef void    (LDAP_C LDAP_CALLBACK LDAP_X_EXTIOF_DISPOSEHANDLE_CALLBACK)(
+            LDAP *ld, struct lextiof_session_private *sessionarg );
+
+
+/* Structure to hold extended I/O function pointers:
+ */
+struct ldap_x_ext_io_fns {
+        /* lextiof_size should always be set to LDAP_X_EXTIO_FNS_SIZE */
+        int                                     lextiof_size;
+        LDAP_X_EXTIOF_CONNECT_CALLBACK          *lextiof_connect;
+        LDAP_X_EXTIOF_CLOSE_CALLBACK            *lextiof_close;
+        LDAP_X_EXTIOF_READ_CALLBACK             *lextiof_read;
+        LDAP_X_EXTIOF_WRITE_CALLBACK            *lextiof_write;
+        LDAP_X_EXTIOF_POLL_CALLBACK             *lextiof_poll;
+        LDAP_X_EXTIOF_NEWHANDLE_CALLBACK        *lextiof_newhandle;
+        LDAP_X_EXTIOF_DISPOSEHANDLE_CALLBACK    *lextiof_disposehandle;
+        void                                    *lextiof_session_arg;
+        LDAP_X_EXTIOF_WRITEV_CALLBACK           *lextiof_writev;
+};
+#define LDAP_X_EXTIO_FNS_SIZE   sizeof(struct ldap_x_ext_io_fns)
+
+/*
+ * Utility functions for parsing space-separated host lists (useful for
+ * implementing an extended I/O CONNECT callback function).
+ */
+struct ldap_x_hostlist_status;
+LDAP_API(int) LDAP_CALL ldap_x_hostlist_first( const char *hostlist,
+        int defport, char **hostp, int *portp /* host byte order */,
+        struct ldap_x_hostlist_status **statusp );
+LDAP_API(int) LDAP_CALL ldap_x_hostlist_next( char **hostp,
+        int *portp /* host byte order */, struct ldap_x_hostlist_status *status
+);
+LDAP_API(void) LDAP_CALL ldap_x_hostlist_statusfree(
+        struct ldap_x_hostlist_status *status );
+
+/*
+ * Client side sorting of entries (an API extension --
+ * LDAP_API_FEATURE_X_CLIENT_SIDE_SORT)
+ */
+/*
+ * Client side sorting callback functions:
+ */
+typedef const struct berval* (LDAP_C LDAP_CALLBACK
+        LDAP_KEYGEN_CALLBACK)( void *arg, LDAP *ld, LDAPMessage *entry );
+typedef int (LDAP_C LDAP_CALLBACK
+        LDAP_KEYCMP_CALLBACK)( void *arg, const struct berval*,
+        const struct berval* );
+typedef void (LDAP_C LDAP_CALLBACK
+        LDAP_KEYFREE_CALLBACK)( void *arg, const struct berval* );
+typedef int (LDAP_C LDAP_CALLBACK
+        LDAP_CMP_CALLBACK)(const char *val1, const char *val2);
+typedef int (LDAP_C LDAP_CALLBACK
+        LDAP_VALCMP_CALLBACK)(const char **val1p, const char **val2p);
+
+/*
+ * Client side sorting functions:
+ */
+LDAP_API(int) LDAP_CALL ldap_keysort_entries( LDAP *ld, LDAPMessage **chain,
+        void *arg, LDAP_KEYGEN_CALLBACK *gen, LDAP_KEYCMP_CALLBACK *cmp,
+        LDAP_KEYFREE_CALLBACK *fre );
+LDAP_API(int) LDAP_CALL ldap_multisort_entries( LDAP *ld, LDAPMessage **chain,
+        char **attr, LDAP_CMP_CALLBACK *cmp );
+LDAP_API(int) LDAP_CALL ldap_sort_entries( LDAP *ld, LDAPMessage **chain,
+        char *attr, LDAP_CMP_CALLBACK *cmp );
+LDAP_API(int) LDAP_CALL ldap_sort_values( LDAP *ld, char **vals,
+        LDAP_VALCMP_CALLBACK *cmp );
+LDAP_API(int) LDAP_C LDAP_CALLBACK ldap_sort_strcasecmp( const char **a,
+        const char **b );
+
+
+/*
+ * Filter functions and definitions (an API extension --
+ * LDAP_API_FEATURE_X_FILTER_FUNCTIONS)
+ */
+/*
+ * Structures, constants, and types for filter utility routines:
+ */
+typedef struct ldap_filt_info {
+        char                    *lfi_filter;
+        char                    *lfi_desc;
+        int                     lfi_scope;      /* LDAP_SCOPE_BASE, etc */
+        int                     lfi_isexact;    /* exact match filter? */
+        struct ldap_filt_info   *lfi_next;
+} LDAPFiltInfo;
+
+#define LDAP_FILT_MAXSIZ        1024
+
+typedef struct ldap_filt_list LDAPFiltList; /* opaque filter list handle */
+typedef struct ldap_filt_desc LDAPFiltDesc; /* opaque filter desc handle */
+
+/*
+ * Filter utility functions:
+ */
+LDAP_API(LDAPFiltDesc *) LDAP_CALL ldap_init_getfilter( char *fname );
+LDAP_API(LDAPFiltDesc *) LDAP_CALL ldap_init_getfilter_buf( char *buf,
+        long buflen );
+LDAP_API(LDAPFiltInfo *) LDAP_CALL ldap_getfirstfilter( LDAPFiltDesc *lfdp,
+        char *tagpat, char *value );
+LDAP_API(LDAPFiltInfo *) LDAP_CALL ldap_getnextfilter( LDAPFiltDesc *lfdp );
+LDAP_API(int) LDAP_CALL ldap_set_filter_additions( LDAPFiltDesc *lfdp,
+        char *prefix, char *suffix );
+LDAP_API(int) LDAP_CALL ldap_create_filter( char *buf, unsigned long buflen,
+        char *pattern, char *prefix, char *suffix, char *attr,
+        char *value, char **valwords );
+LDAP_API(void) LDAP_CALL ldap_getfilter_free( LDAPFiltDesc *lfdp );
+
+/*
+ * Friendly mapping structure and routines (an API extension)
+ */
+typedef struct friendly {
+        char    *f_unfriendly;
+        char    *f_friendly;
+} *FriendlyMap;
+LDAP_API(char *) LDAP_CALL ldap_friendly_name( char *filename, char *name,
+        FriendlyMap *map );
+LDAP_API(void) LDAP_CALL ldap_free_friendlymap( FriendlyMap *map );
+
+/*
+ * In Memory Cache (an API extension -- LDAP_API_FEATURE_X_MEMCACHE)
+ */
+typedef struct ldapmemcache  LDAPMemCache;  /* opaque in-memory cache handle */
+
+LDAP_API(int) LDAP_CALL ldap_memcache_init( unsigned long ttl,
+        unsigned long size, char **baseDNs, struct ldap_thread_fns *thread_fns,
+        LDAPMemCache **cachep );
+LDAP_API(int) LDAP_CALL ldap_memcache_set( LDAP *ld, LDAPMemCache *cache );
+LDAP_API(int) LDAP_CALL ldap_memcache_get( LDAP *ld, LDAPMemCache **cachep );
+LDAP_API(void) LDAP_CALL ldap_memcache_flush( LDAPMemCache *cache, char *dn,
+        int scope );
+LDAP_API(void) LDAP_CALL ldap_memcache_flush_results( LDAPMemCache *cache,
+        char *dn, int scope );
+LDAP_API(void) LDAP_CALL ldap_memcache_destroy( LDAPMemCache *cache );
+LDAP_API(void) LDAP_CALL ldap_memcache_update( LDAPMemCache *cache );
+
+/*
+ * Timeout value for nonblocking connect call
+ */
+#define LDAP_X_OPT_CONNECT_TIMEOUT    (LDAP_OPT_PRIVATE_EXTENSION_BASE + 0x0F01)
+        /* 0x4000 + 0x0F01 = 0x4F01 = 20225 - API extension */
+
+/* 
+ * Socket buffer structure associated to the LDAP connection
+ */
+#define LDAP_X_OPT_SOCKBUF            (LDAP_OPT_PRIVATE_EXTENSION_BASE + 0x0F03)
+	/* 0x4000 + 0x0F03 = 0x4F03 = 20227 - API extension */
+
+/*
+ * Memory allocation callback functions (an API extension --
+ * LDAP_API_FEATURE_X_MEMALLOC_FUNCTIONS).  These are global and can
+ * not be set on a per-LDAP session handle basis.  Install your own
+ * functions by making a call like this:
+ *    ldap_set_option( NULL, LDAP_OPT_MEMALLOC_FN_PTRS, &memalloc_fns );
+ *
+ * look in lber.h for the function typedefs themselves.
+ */
+#define LDAP_OPT_MEMALLOC_FN_PTRS       0x61    /* 97 - API extension */
+
+struct ldap_memalloc_fns {
+        LDAP_MALLOC_CALLBACK    *ldapmem_malloc;
+        LDAP_CALLOC_CALLBACK    *ldapmem_calloc;
+        LDAP_REALLOC_CALLBACK   *ldapmem_realloc;
+        LDAP_FREE_CALLBACK      *ldapmem_free;
+};
+
+
+/*
+ * Memory allocation functions (an API extension)
+ */
+void *ldap_x_malloc( size_t size );
+void *ldap_x_calloc( size_t nelem, size_t elsize );
+void *ldap_x_realloc( void *ptr, size_t size );
+void ldap_x_free( void *ptr );
+
+/*
+ * Server reconnect (an API extension).
+ */
+#define LDAP_OPT_RECONNECT              0x62    /* 98 - API extension */
+
+
+/*
+ * Extra thread callback functions (an API extension --
+ * LDAP_API_FEATURE_X_EXTHREAD_FUNCTIONS)
+ */
+#define LDAP_OPT_EXTRA_THREAD_FN_PTRS  0x65     /* 101 - API extension */
+
+/*
+ * When bind is called, don't bind if there's a connection open with the same DN
+ */
+#define LDAP_OPT_NOREBIND               0x66    /* 102 - API extension */
+
+typedef int (LDAP_C LDAP_CALLBACK LDAP_TF_MUTEX_TRYLOCK_CALLBACK)( void *m );
+typedef void *(LDAP_C LDAP_CALLBACK LDAP_TF_SEMA_ALLOC_CALLBACK)( void );
+typedef void (LDAP_C LDAP_CALLBACK LDAP_TF_SEMA_FREE_CALLBACK)( void *s );
+typedef int (LDAP_C LDAP_CALLBACK LDAP_TF_SEMA_WAIT_CALLBACK)( void *s );
+typedef int (LDAP_C LDAP_CALLBACK LDAP_TF_SEMA_POST_CALLBACK)( void *s );
+typedef void *(LDAP_C LDAP_CALLBACK LDAP_TF_THREADID_CALLBACK)(void);
+
+struct ldap_extra_thread_fns {
+        LDAP_TF_MUTEX_TRYLOCK_CALLBACK *ltf_mutex_trylock;
+        LDAP_TF_SEMA_ALLOC_CALLBACK *ltf_sema_alloc;
+        LDAP_TF_SEMA_FREE_CALLBACK *ltf_sema_free;
+        LDAP_TF_SEMA_WAIT_CALLBACK *ltf_sema_wait;
+        LDAP_TF_SEMA_POST_CALLBACK *ltf_sema_post;
+        LDAP_TF_THREADID_CALLBACK *ltf_threadid_fn;
+};
+
+/*
+ * Debugging level (an API extension)
+ */
+#define LDAP_OPT_DEBUG_LEVEL            0x6E    /* 110 - API extension */
+/* On UNIX, there's only one copy of ldap_debug */
+/* On NT, each dll keeps its own module_ldap_debug, which */
+/* points to the process' ldap_debug and needs initializing after load */
+#ifdef _WIN32
+extern int              *module_ldap_debug;
+typedef void (*set_debug_level_fn_t)(int*);
+#endif
+
+#ifdef LDAP_DNS
+#define LDAP_OPT_DNS                    0x0C    /* 12 - API extension */
+#endif
+
+/*
+ * UTF-8 routines (should these move into libnls?)
+ */
+/* number of bytes in character */
+LDAP_API(int) LDAP_CALL ldap_utf8len( const char* );
+/* find next character */
+LDAP_API(char*) LDAP_CALL ldap_utf8next( char* );
+/* find previous character */
+LDAP_API(char*) LDAP_CALL ldap_utf8prev( char* );
+/* copy one character */
+LDAP_API(int) LDAP_CALL ldap_utf8copy( char* dst, const char* src );
+/* total number of characters */
+LDAP_API(size_t) LDAP_CALL ldap_utf8characters( const char* );
+/* get one UCS-4 character, and move *src to the next character */
+LDAP_API(unsigned long) LDAP_CALL ldap_utf8getcc( const char** src );
+/* UTF-8 aware strtok_r() */
+LDAP_API(char*) LDAP_CALL ldap_utf8strtok_r( char* src, const char* brk, char**
+next);
+
+/* like isalnum(*s) in the C locale */
+LDAP_API(int) LDAP_CALL ldap_utf8isalnum( char* s );
+/* like isalpha(*s) in the C locale */
+LDAP_API(int) LDAP_CALL ldap_utf8isalpha( char* s );
+/* like isdigit(*s) in the C locale */
+LDAP_API(int) LDAP_CALL ldap_utf8isdigit( char* s );
+/* like isxdigit(*s) in the C locale */
+LDAP_API(int) LDAP_CALL ldap_utf8isxdigit(char* s );
+/* like isspace(*s) in the C locale */
+LDAP_API(int) LDAP_CALL ldap_utf8isspace( char* s );
+
+#define LDAP_UTF8LEN(s)  ((0x80 & *(unsigned char*)(s)) ?   ldap_utf8len (s) : 1)
+#define LDAP_UTF8NEXT(s) ((0x80 & *(unsigned char*)(s)) ?   ldap_utf8next(s) : ( s)+1)
+#define LDAP_UTF8INC(s)  ((0x80 & *(unsigned char*)(s)) ? s=ldap_utf8next(s) : ++s)
+
+#define LDAP_UTF8PREV(s)   ldap_utf8prev(s)
+#define LDAP_UTF8DEC(s) (s=ldap_utf8prev(s))
+
+#define LDAP_UTF8COPY(d,s) ((0x80 & *(unsigned char*)(s)) ? ldap_utf8copy(d,s) : ((*(d) = *(s)), 1))
+#define LDAP_UTF8GETCC(s) ((0x80 & *(unsigned char*)(s)) ? ldap_utf8getcc (&s) : *s++)
+#define LDAP_UTF8GETC(s) ((0x80 & *(unsigned char*)(s)) ? ldap_utf8getcc ((const char**)&s) : *s++)
+
+/* SASL options */
+#define LDAP_OPT_X_SASL_MECH            0x6100
+#define LDAP_OPT_X_SASL_REALM           0x6101
+#define LDAP_OPT_X_SASL_AUTHCID         0x6102
+#define LDAP_OPT_X_SASL_AUTHZID         0x6103
+#define LDAP_OPT_X_SASL_SSF             0x6104 /* read-only */
+#define LDAP_OPT_X_SASL_SSF_EXTERNAL    0x6105 /* write-only */
+#define LDAP_OPT_X_SASL_SECPROPS        0x6106 /* write-only */
+#define LDAP_OPT_X_SASL_SSF_MIN         0x6107
+#define LDAP_OPT_X_SASL_SSF_MAX         0x6108
+#define LDAP_OPT_X_SASL_MAXBUFSIZE      0x6109
+
+/* ldap_interactive_bind_s Interaction flags
+ *  Interactive: prompt always - REQUIRED
+ */
+#define LDAP_SASL_AUTOMATIC     0U /* only prompt for missing items not supplied as defaults */
+#define LDAP_SASL_INTERACTIVE   1U /* prompt for everything and print defaults, if any */
+#define LDAP_SASL_QUIET         2U /* no prompts - only use defaults (e.g. for non-interactive apps) */
+
+/*
+ * V3 SASL Interaction Function Callback Prototype
+ *      when using Cyrus SASL, interact is pointer to sasl_interact_t
+ *  should likely passed in a control (and provided controls)
+ */
+typedef int (LDAP_SASL_INTERACT_PROC)
+        (LDAP *ld, unsigned flags, void* defaults, void *interact );
+
+LDAP_API(int) LDAP_CALL ldap_sasl_interactive_bind_s (
+        LDAP *ld,
+        const char *dn, /* usually NULL */
+        const char *saslMechanism,
+        LDAPControl **serverControls,
+        LDAPControl **clientControls,
+
+        /* should be client controls */
+        unsigned flags,
+        LDAP_SASL_INTERACT_PROC *proc,
+        void *defaults );
+
+LDAP_API(int) LDAP_CALL ldap_sasl_interactive_bind_ext_s (
+        LDAP *ld,
+        const char *dn, /* usually NULL */
+        const char *saslMechanism,
+        LDAPControl **serverControls,
+        LDAPControl **clientControls,
+
+        /* should be client controls */
+        unsigned flags,
+        LDAP_SASL_INTERACT_PROC *proc,
+        void *defaults,
+        LDAPControl ***responseControls );
+
+/*
+ * Password modify functions
+ */
+LDAP_API(int) LDAP_CALL ldap_passwd( LDAP *ld, struct berval *userid,
+	struct berval *oldpasswd, struct berval *newpasswd,
+	LDAPControl **serverctrls, LDAPControl **clientctrls,
+	int *msgidp );
+
+LDAP_API(int) LDAP_CALL ldap_passwd_s( LDAP *ld, struct berval *userid,
+	struct berval *oldpasswd, struct berval *newpasswd,
+	struct berval *genpasswd, LDAPControl **serverctrls,
+	LDAPControl **clientctrls );
+
+LDAP_API(int) LDAP_CALL ldap_parse_passwd( LDAP *ld, LDAPMessage *result,
+	struct berval *genpasswd );
+    
+/*
+ * in reslist.c
+ */
+LDAP_API(LDAPMessage *) LDAP_CALL ldap_delete_result_entry( LDAPMessage **list, LDAPMessage *e );
+LDAP_API(void) LDAP_CALL ldap_add_result_entry( LDAPMessage **list, LDAPMessage *e );
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _LDAP_EXTENSION_H */
+
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/include/ldap-platform.h
@@ -0,0 +1,91 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+/* ldap-platform.h - platform transparency */
+
+#ifndef _LDAP_PLATFORM_H
+#define _LDAP_PLATFORM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined (WIN32) || defined (_WIN32) || defined( _CONSOLE ) 
+#include <windows.h>
+#  if defined( _WINDOWS )
+#  include <winsock.h>
+#  endif
+#elif defined(macintosh)
+#ifndef LDAP_TYPE_TIMEVAL_DEFINED
+#include <utime.h>
+#endif
+#ifndef LDAP_TYPE_SOCKET_DEFINED	/* API extension */
+#include "macsocket.h"
+#endif
+#else /* everything else, e.g., Unix */
+#ifndef LDAP_TYPE_TIMEVAL_DEFINED
+#include <sys/time.h>
+#endif
+#ifndef LDAP_TYPE_SOCKET_DEFINED	/* API extension */
+#include <sys/types.h>
+#include <sys/socket.h>
+#endif
+#endif
+
+#ifdef _AIX
+#include <sys/select.h>
+#endif /* _AIX */
+
+#ifdef XP_OS2
+#include <sys/select.h>
+#endif /* XP_OS2 */
+
+/*
+ * LDAP_API macro definition:
+ */
+#ifndef LDAP_API
+#if defined( _WINDOWS ) || defined( _WIN32 )
+#define LDAP_API(rt) rt
+#else /* _WINDOWS */
+#define LDAP_API(rt) rt
+#endif /* _WINDOWS */
+#endif /* LDAP_API */
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _LDAP_PLATFORM_H */
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/include/ldap-standard-tmpl.h
@@ -0,0 +1,458 @@
+/* This file is a template.  The generated file is ldap-standard.h>
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+/* ldap-standard.h - standards base header file for libldap */
+/* This file contain the defines and function prototypes matching */
+/* very closely to the latest LDAP C API draft */
+ 
+#ifndef _LDAP_STANDARD_H
+#define _LDAP_STANDARD_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ldap-platform.h"
+
+#include "lber.h"
+
+#define LDAP_PORT       	389
+#define LDAPS_PORT      	636
+#define LDAP_VERSION2   	2
+#define LDAP_VERSION3   	3
+#define LDAP_VERSION_MIN	LDAP_VERSION1
+#define LDAP_VERSION_MAX	LDAP_VERSION3
+
+#define LDAP_VENDOR_VERSION	{{LDAP_VENDOR_VERSION}}	/* version # * 100 */
+#define LDAP_VENDOR_NAME	"{{LDAP_VENDOR_NAME}}"
+/*
+ * The following will be an RFC number once the LDAP C API Internet Draft
+ * is published as a Proposed Standard RFC.  For now we use 2000 + the
+ * draft revision number (currently 5) since we are close to compliance
+ * with revision 5 of the draft.
+ */
+#define LDAP_API_VERSION	2005
+
+/* special values that may appear in the attributes field of a SearchRequest.
+ */
+#define LDAP_NO_ATTRS		"1.1"
+#define LDAP_ALL_USER_ATTRS	"*"
+
+/*
+ * Standard options (used with ldap_set_option() and ldap_get_option):
+ */
+#define LDAP_OPT_API_INFO               0x00	/*  0 */
+#define LDAP_OPT_DEREF                  0x02	/*  2 */
+#define LDAP_OPT_SIZELIMIT              0x03	/*  3 */
+#define LDAP_OPT_TIMELIMIT              0x04	/*  4 */
+#define LDAP_OPT_REFERRALS              0x08	/*  8 */
+#define LDAP_OPT_RESTART                0x09	/*  9 */
+#define LDAP_OPT_PROTOCOL_VERSION	0x11	/* 17 */
+#define LDAP_OPT_SERVER_CONTROLS	0x12	/* 18 */
+#define LDAP_OPT_CLIENT_CONTROLS	0x13	/* 19 */
+#define LDAP_OPT_API_FEATURE_INFO	0x15	/* 21 */
+#define LDAP_OPT_HOST_NAME		0x30	/* 48 */
+#define LDAP_OPT_ERROR_NUMBER		0x31	/* 49 */
+#define LDAP_OPT_ERROR_STRING		0x32	/* 50 */
+#define LDAP_OPT_MATCHED_DN		0x33	/* 51 */
+
+/*
+ * Well-behaved private and experimental extensions will use option values
+ * between 0x4000 (16384) and 0x7FFF (32767) inclusive.
+ */
+#define LDAP_OPT_PRIVATE_EXTENSION_BASE	0x4000	/* to 0x7FFF inclusive */
+
+/* for on/off options */
+#define LDAP_OPT_ON     ((void *)1)
+#define LDAP_OPT_OFF    ((void *)0)
+
+typedef struct ldap     LDAP;           /* opaque connection handle */
+typedef struct ldapmsg  LDAPMessage;    /* opaque result/entry handle */
+
+/* structure representing an LDAP modification */
+typedef struct ldapmod {
+	int             mod_op;         /* kind of mod + form of values*/
+#define LDAP_MOD_ADD            0x00
+#define LDAP_MOD_DELETE         0x01
+#define LDAP_MOD_REPLACE        0x02
+#define LDAP_MOD_BVALUES        0x80
+	char            *mod_type;      /* attribute name to modify */
+	union mod_vals_u {
+		char            **modv_strvals;
+		struct berval   **modv_bvals;
+	} mod_vals;                     /* values to add/delete/replace */
+#define mod_values      mod_vals.modv_strvals
+#define mod_bvalues     mod_vals.modv_bvals
+} LDAPMod;
+
+
+/*
+ * structure for holding ldapv3 controls
+ */
+typedef struct ldapcontrol {
+    char            *ldctl_oid;
+    struct berval   ldctl_value;
+    char            ldctl_iscritical;
+} LDAPControl;
+
+
+/*
+ * LDAP API information.  Can be retrieved by using a sequence like:
+ *
+ *    LDAPAPIInfo ldai;
+ *    ldai.ldapai_info_version = LDAP_API_INFO_VERSION;
+ *    if ( ldap_get_option( NULL, LDAP_OPT_API_INFO, &ldia ) == 0 ) ...
+ */
+#define LDAP_API_INFO_VERSION		1
+typedef struct ldapapiinfo {
+    int  ldapai_info_version;     /* version of this struct (1) */
+    int  ldapai_api_version;      /* revision of API supported */
+    int  ldapai_protocol_version; /* highest LDAP version supported */
+    char **ldapai_extensions;     /* names of API extensions */
+    char *ldapai_vendor_name;     /* name of supplier */
+    int  ldapai_vendor_version;   /* supplier-specific version times 100 */
+} LDAPAPIInfo;
+
+
+/*
+ * LDAP API extended features info.  Can be retrieved by using a sequence like:
+ *
+ *    LDAPAPIFeatureInfo ldfi;
+ *    ldfi.ldapaif_info_version = LDAP_FEATURE_INFO_VERSION;
+ *    ldfi.ldapaif_name = "VIRTUAL_LIST_VIEW";
+ *    if ( ldap_get_option( NULL, LDAP_OPT_API_FEATURE_INFO, &ldfi ) == 0 ) ...
+ */
+#define LDAP_FEATURE_INFO_VERSION	1
+typedef struct ldap_apifeature_info {
+    int   ldapaif_info_version;	/* version of this struct (1) */
+    char  *ldapaif_name;	/* name of supported feature */
+    int   ldapaif_version;	/* revision of supported feature */
+} LDAPAPIFeatureInfo;
+
+
+/* possible result types a server can return */
+#define LDAP_RES_BIND                   0x61L	/* 97 */
+#define LDAP_RES_SEARCH_ENTRY           0x64L	/* 100 */
+#define LDAP_RES_SEARCH_RESULT          0x65L	/* 101 */
+#define LDAP_RES_MODIFY                 0x67L	/* 103 */
+#define LDAP_RES_ADD                    0x69L	/* 105 */
+#define LDAP_RES_DELETE                 0x6BL	/* 107 */
+#define LDAP_RES_MODDN			0x6DL	/* 109 */
+#define LDAP_RES_COMPARE                0x6FL	/* 111 */
+#define LDAP_RES_SEARCH_REFERENCE       0x73L	/* 115 */
+#define LDAP_RES_EXTENDED               0x78L	/* 120 */
+
+/* Special values for ldap_result() "msgid" parameter */
+#define LDAP_RES_ANY                (-1)
+#define LDAP_RES_UNSOLICITED		0
+
+/* built-in SASL methods */
+#define LDAP_SASL_SIMPLE	0	/* special value used for simple bind */
+
+/* search scopes */
+#define LDAP_SCOPE_BASE         0x00
+#define LDAP_SCOPE_ONELEVEL     0x01
+#define LDAP_SCOPE_SUBTREE      0x02
+
+/* alias dereferencing */
+#define LDAP_DEREF_NEVER        0x00
+#define LDAP_DEREF_SEARCHING    0x01
+#define LDAP_DEREF_FINDING      0x02
+#define LDAP_DEREF_ALWAYS       0x03
+
+/* predefined size/time limits */
+#define LDAP_NO_LIMIT           0
+
+/* allowed values for "all" ldap_result() parameter */
+#define LDAP_MSG_ONE		0x00
+#define LDAP_MSG_ALL		0x01
+#define LDAP_MSG_RECEIVED	0x02
+
+/* possible error codes we can be returned */
+#define LDAP_SUCCESS                    0x00	/* 0 */
+#define LDAP_OPERATIONS_ERROR           0x01	/* 1 */
+#define LDAP_PROTOCOL_ERROR             0x02	/* 2 */
+#define LDAP_TIMELIMIT_EXCEEDED         0x03	/* 3 */
+#define LDAP_SIZELIMIT_EXCEEDED         0x04	/* 4 */
+#define LDAP_COMPARE_FALSE              0x05	/* 5 */
+#define LDAP_COMPARE_TRUE               0x06	/* 6 */
+#define LDAP_STRONG_AUTH_NOT_SUPPORTED  0x07	/* 7 */
+#define LDAP_STRONG_AUTH_REQUIRED       0x08	/* 8 */
+#define LDAP_REFERRAL                   0x0a	/* 10 - LDAPv3 */
+#define LDAP_ADMINLIMIT_EXCEEDED	0x0b	/* 11 - LDAPv3 */
+#define LDAP_UNAVAILABLE_CRITICAL_EXTENSION  0x0c /* 12 - LDAPv3 */
+#define LDAP_CONFIDENTIALITY_REQUIRED	0x0d	/* 13 */
+#define LDAP_SASL_BIND_IN_PROGRESS	0x0e	/* 14 - LDAPv3 */
+
+#define LDAP_NO_SUCH_ATTRIBUTE          0x10	/* 16 */
+#define LDAP_UNDEFINED_TYPE             0x11	/* 17 */
+#define LDAP_INAPPROPRIATE_MATCHING     0x12	/* 18 */
+#define LDAP_CONSTRAINT_VIOLATION       0x13	/* 19 */
+#define LDAP_TYPE_OR_VALUE_EXISTS       0x14	/* 20 */
+#define LDAP_INVALID_SYNTAX             0x15	/* 21 */
+
+#define LDAP_NO_SUCH_OBJECT             0x20	/* 32 */
+#define LDAP_ALIAS_PROBLEM              0x21	/* 33 */
+#define LDAP_INVALID_DN_SYNTAX          0x22	/* 34 */
+#define LDAP_IS_LEAF                    0x23	/* 35 (not used in LDAPv3) */
+#define LDAP_ALIAS_DEREF_PROBLEM        0x24	/* 36 */
+
+#define LDAP_INAPPROPRIATE_AUTH         0x30	/* 48 */
+#define LDAP_INVALID_CREDENTIALS        0x31	/* 49 */
+#define LDAP_INSUFFICIENT_ACCESS        0x32	/* 50 */
+#define LDAP_BUSY                       0x33	/* 51 */
+#define LDAP_UNAVAILABLE                0x34	/* 52 */
+#define LDAP_UNWILLING_TO_PERFORM       0x35	/* 53 */
+#define LDAP_LOOP_DETECT                0x36	/* 54 */
+
+#define LDAP_NAMING_VIOLATION           0x40	/* 64 */
+#define LDAP_OBJECT_CLASS_VIOLATION     0x41	/* 65 */
+#define LDAP_NOT_ALLOWED_ON_NONLEAF     0x42	/* 66 */
+#define LDAP_NOT_ALLOWED_ON_RDN         0x43	/* 67 */
+#define LDAP_ALREADY_EXISTS             0x44	/* 68 */
+#define LDAP_NO_OBJECT_CLASS_MODS       0x45	/* 69 */
+#define LDAP_RESULTS_TOO_LARGE          0x46	/* 70 - CLDAP */
+#define LDAP_AFFECTS_MULTIPLE_DSAS      0x47	/* 71 */
+
+#define LDAP_OTHER                      0x50	/* 80 */
+#define LDAP_SERVER_DOWN                0x51	/* 81 */
+#define LDAP_LOCAL_ERROR                0x52	/* 82 */
+#define LDAP_ENCODING_ERROR             0x53	/* 83 */
+#define LDAP_DECODING_ERROR             0x54	/* 84 */
+#define LDAP_TIMEOUT                    0x55	/* 85 */
+#define LDAP_AUTH_UNKNOWN               0x56	/* 86 */
+#define LDAP_FILTER_ERROR               0x57	/* 87 */
+#define LDAP_USER_CANCELLED             0x58	/* 88 */
+#define LDAP_PARAM_ERROR                0x59	/* 89 */
+#define LDAP_NO_MEMORY                  0x5a	/* 90 */
+#define LDAP_CONNECT_ERROR              0x5b	/* 91 */
+#define LDAP_NOT_SUPPORTED              0x5c	/* 92 - LDAPv3 */
+#define LDAP_CONTROL_NOT_FOUND		0x5d	/* 93 - LDAPv3 */
+#define LDAP_NO_RESULTS_RETURNED	0x5e	/* 94 - LDAPv3 */
+#define LDAP_MORE_RESULTS_TO_RETURN	0x5f	/* 95 - LDAPv3 */
+#define LDAP_CLIENT_LOOP		0x60	/* 96 - LDAPv3 */
+#define LDAP_REFERRAL_LIMIT_EXCEEDED	0x61	/* 97 - LDAPv3 */
+
+/*
+ * LDAPv3 unsolicited notification messages we know about
+ */
+#define LDAP_NOTICE_OF_DISCONNECTION	"1.3.6.1.4.1.1466.20036"
+
+/*
+ * Client controls we know about
+ */
+#define LDAP_CONTROL_REFERRALS		"1.2.840.113556.1.4.616"
+
+/*
+ * Initializing an ldap sesssion, set session handle options, and
+ * closing an ldap session functions
+ *
+ * NOTE: If you want to use IPv6, you must use prldap creating a LDAP handle
+ * with prldap_init instead of ldap_init. Or install the NSPR functions
+ * by calling prldap_install_routines. (See the nspr samples in examples)
+ */
+LDAP_API(LDAP *) LDAP_CALL ldap_init( const char *defhost, int defport );
+LDAP_API(int) LDAP_CALL ldap_set_option( LDAP *ld, int option,
+	const void *optdata );
+LDAP_API(int) LDAP_CALL ldap_get_option( LDAP *ld, int option, void *optdata );
+LDAP_API(int) LDAP_CALL ldap_unbind( LDAP *ld );
+LDAP_API(int) LDAP_CALL ldap_unbind_s( LDAP *ld );
+
+/*
+ * perform ldap operations
+ */
+LDAP_API(int) LDAP_CALL ldap_abandon( LDAP *ld, int msgid );
+LDAP_API(int) LDAP_CALL ldap_add( LDAP *ld, const char *dn, LDAPMod **attrs );
+LDAP_API(int) LDAP_CALL ldap_add_s( LDAP *ld, const char *dn, LDAPMod **attrs );
+LDAP_API(int) LDAP_CALL ldap_simple_bind( LDAP *ld, const char *who,
+	const char *passwd );
+LDAP_API(int) LDAP_CALL ldap_simple_bind_s( LDAP *ld, const char *who,
+	const char *passwd );
+LDAP_API(int) LDAP_CALL ldap_modify( LDAP *ld, const char *dn, LDAPMod **mods );
+LDAP_API(int) LDAP_CALL ldap_modify_s( LDAP *ld, const char *dn, 
+	LDAPMod **mods );
+LDAP_API(int) LDAP_CALL ldap_compare( LDAP *ld, const char *dn,
+	const char *attr, const char *value );
+LDAP_API(int) LDAP_CALL ldap_compare_s( LDAP *ld, const char *dn, 
+	const char *attr, const char *value );
+LDAP_API(int) LDAP_CALL ldap_delete( LDAP *ld, const char *dn );
+LDAP_API(int) LDAP_CALL ldap_delete_s( LDAP *ld, const char *dn );
+LDAP_API(int) LDAP_CALL ldap_search( LDAP *ld, const char *base, int scope,
+	const char *filter, char **attrs, int attrsonly );
+LDAP_API(int) LDAP_CALL ldap_search_s( LDAP *ld, const char *base, int scope,
+	const char *filter, char **attrs, int attrsonly, LDAPMessage **res );
+LDAP_API(int) LDAP_CALL ldap_search_st( LDAP *ld, const char *base, int scope,
+	const char *filter, char **attrs, int attrsonly,
+	struct timeval *timeout, LDAPMessage **res );
+
+/*
+ * obtain result from ldap operation
+ */
+LDAP_API(int) LDAP_CALL ldap_result( LDAP *ld, int msgid, int all,
+	struct timeval *timeout, LDAPMessage **result );
+
+/*
+ * peeking inside LDAP Messages and deallocating LDAP Messages
+ */
+LDAP_API(int) LDAP_CALL ldap_msgfree( LDAPMessage *lm );
+LDAP_API(int) LDAP_CALL ldap_msgid( LDAPMessage *lm );
+LDAP_API(int) LDAP_CALL ldap_msgtype( LDAPMessage *lm );
+
+
+/*
+ * Routines to parse/deal with results and errors returned
+ */
+LDAP_API(char *) LDAP_CALL ldap_err2string( int err );
+LDAP_API(LDAPMessage *) LDAP_CALL ldap_first_entry( LDAP *ld, 
+	LDAPMessage *chain );
+LDAP_API(LDAPMessage *) LDAP_CALL ldap_next_entry( LDAP *ld, 
+	LDAPMessage *entry );
+LDAP_API(int) LDAP_CALL ldap_count_entries( LDAP *ld, LDAPMessage *chain );
+LDAP_API(char *) LDAP_CALL ldap_get_dn( LDAP *ld, LDAPMessage *entry );
+LDAP_API(char *) LDAP_CALL ldap_dn2ufn( const char *dn );
+LDAP_API(char **) LDAP_CALL ldap_explode_dn( const char *dn, 
+	const int notypes );
+LDAP_API(char **) LDAP_CALL ldap_explode_rdn( const char *rdn, 
+	const int notypes );
+LDAP_API(char *) LDAP_CALL ldap_first_attribute( LDAP *ld, LDAPMessage *entry,
+	BerElement **ber );
+LDAP_API(char *) LDAP_CALL ldap_next_attribute( LDAP *ld, LDAPMessage *entry,
+	BerElement *ber );
+LDAP_API(char **) LDAP_CALL ldap_get_values( LDAP *ld, LDAPMessage *entry,
+	const char *target );
+LDAP_API(struct berval **) LDAP_CALL ldap_get_values_len( LDAP *ld,
+	LDAPMessage *entry, const char *target );
+LDAP_API(int) LDAP_CALL ldap_count_values( char **vals );
+LDAP_API(int) LDAP_CALL ldap_count_values_len( struct berval **vals );
+LDAP_API(void) LDAP_CALL ldap_value_free( char **vals );
+LDAP_API(void) LDAP_CALL ldap_value_free_len( struct berval **vals );
+LDAP_API(void) LDAP_CALL ldap_memfree( void *p );
+
+
+/*
+ * LDAPv3 extended operation calls
+ */
+/*
+ * Note: all of the new asynchronous calls return an LDAP error code,
+ * not a message id.  A message id is returned via the int *msgidp
+ * parameter (usually the last parameter) if appropriate.
+ */
+LDAP_API(int) LDAP_CALL ldap_abandon_ext( LDAP *ld, int msgid,
+	LDAPControl **serverctrls, LDAPControl **clientctrls );
+LDAP_API(int) LDAP_CALL ldap_add_ext( LDAP *ld, const char *dn, LDAPMod **attrs,
+	LDAPControl **serverctrls, LDAPControl **clientctrls, int *msgidp );
+LDAP_API(int) LDAP_CALL ldap_add_ext_s( LDAP *ld, const char *dn,
+	LDAPMod **attrs, LDAPControl **serverctrls, LDAPControl **clientctrls );
+LDAP_API(int) LDAP_CALL ldap_sasl_bind( LDAP *ld, const char *dn,
+	const char *mechanism, const struct berval *cred,
+	LDAPControl **serverctrls, LDAPControl **clientctrls, int *msgidp );
+LDAP_API(int) LDAP_CALL ldap_sasl_bind_s( LDAP *ld, const char *dn,
+	const char *mechanism, const struct berval *cred,
+	LDAPControl **serverctrls, LDAPControl **clientctrls,
+	struct berval **servercredp );
+LDAP_API(int) LDAP_CALL ldap_modify_ext( LDAP *ld, const char *dn,
+	LDAPMod **mods, LDAPControl **serverctrls, LDAPControl **clientctrls,
+	int *msgidp );
+LDAP_API(int) LDAP_CALL ldap_modify_ext_s( LDAP *ld, const char *dn,
+	LDAPMod **mods, LDAPControl **serverctrls, LDAPControl **clientctrls );
+LDAP_API(int) LDAP_CALL ldap_rename( LDAP *ld, const char *dn,
+	const char *newrdn, const char *newparent, int deleteoldrdn,
+	LDAPControl **serverctrls, LDAPControl **clientctrls, int *msgidp );
+LDAP_API(int) LDAP_CALL ldap_rename_s( LDAP *ld, const char *dn,
+	const char *newrdn, const char *newparent, int deleteoldrdn,
+	LDAPControl **serverctrls, LDAPControl **clientctrls );
+LDAP_API(int) LDAP_CALL ldap_compare_ext( LDAP *ld, const char *dn,
+	const char *attr, const struct berval *bvalue,
+	LDAPControl **serverctrls, LDAPControl **clientctrls, int *msgidp );
+LDAP_API(int) LDAP_CALL ldap_compare_ext_s( LDAP *ld, const char *dn,
+	const char *attr, const struct berval *bvalue,
+	LDAPControl **serverctrls, LDAPControl **clientctrls );
+LDAP_API(int) LDAP_CALL ldap_delete_ext( LDAP *ld, const char *dn,
+	LDAPControl **serverctrls, LDAPControl **clientctrls, int *msgidp );
+LDAP_API(int) LDAP_CALL ldap_delete_ext_s( LDAP *ld, const char *dn,
+	LDAPControl **serverctrls, LDAPControl **clientctrls );
+LDAP_API(int) LDAP_CALL ldap_search_ext( LDAP *ld, const char *base,
+	int scope, const char *filter, char **attrs, int attrsonly,
+	LDAPControl **serverctrls, LDAPControl **clientctrls,
+	struct timeval *timeoutp, int sizelimit, int *msgidp );
+LDAP_API(int) LDAP_CALL ldap_search_ext_s( LDAP *ld, const char *base,
+	int scope, const char *filter, char **attrs, int attrsonly,
+	LDAPControl **serverctrls, LDAPControl **clientctrls,
+	struct timeval *timeoutp, int sizelimit, LDAPMessage **res );
+LDAP_API(int) LDAP_CALL ldap_extended_operation( LDAP *ld,
+	const char *requestoid, const struct berval *requestdata,
+	LDAPControl **serverctrls, LDAPControl **clientctrls, int *msgidp );
+LDAP_API(int) LDAP_CALL ldap_extended_operation_s( LDAP *ld,
+	const char *requestoid, const struct berval *requestdata,
+	LDAPControl **serverctrls, LDAPControl **clientctrls,
+	char **retoidp, struct berval **retdatap );
+LDAP_API(int) LDAP_CALL ldap_unbind_ext( LDAP *ld, LDAPControl **serverctrls,
+	LDAPControl **clientctrls );
+
+
+/*
+ * LDAPv3 extended parsing / result handling calls
+ */
+LDAP_API(int) LDAP_CALL ldap_parse_sasl_bind_result( LDAP *ld,
+	LDAPMessage *res, struct berval **servercredp, int freeit );
+LDAP_API(int) LDAP_CALL ldap_parse_result( LDAP *ld, LDAPMessage *res,
+	int *errcodep, char **matcheddnp, char **errmsgp, char ***referralsp,
+	LDAPControl ***serverctrlsp, int freeit );
+LDAP_API(int) LDAP_CALL ldap_parse_extended_result( LDAP *ld, LDAPMessage *res,
+	char **retoidp, struct berval **retdatap, int freeit );
+LDAP_API(LDAPMessage *) LDAP_CALL ldap_first_message( LDAP *ld,
+	LDAPMessage *res );
+LDAP_API(LDAPMessage *) LDAP_CALL ldap_next_message( LDAP *ld,	
+	LDAPMessage *msg );
+LDAP_API(int) LDAP_CALL ldap_count_messages( LDAP *ld, LDAPMessage *res );
+LDAP_API(LDAPMessage *) LDAP_CALL ldap_first_reference( LDAP *ld,
+	LDAPMessage *res );
+LDAP_API(LDAPMessage *) LDAP_CALL ldap_next_reference( LDAP *ld,
+	LDAPMessage *ref );
+LDAP_API(int) LDAP_CALL ldap_count_references( LDAP *ld, LDAPMessage *res );
+LDAP_API(int) LDAP_CALL ldap_parse_reference( LDAP *ld, LDAPMessage *ref,
+	char ***referralsp, LDAPControl ***serverctrlsp, int freeit );
+LDAP_API(int) LDAP_CALL ldap_get_entry_controls( LDAP *ld, LDAPMessage *entry,
+	LDAPControl ***serverctrlsp );
+LDAP_API(void) LDAP_CALL ldap_control_free( LDAPControl *ctrl );
+LDAP_API(void) LDAP_CALL ldap_controls_free( LDAPControl **ctrls );
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _LDAP_STANDARD_H */
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/include/ldap-to-be-deprecated.h
@@ -0,0 +1,193 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+/* ldap-to-be-deprecated.h - functions and declaration which will be
+ * deprecated in a future release.
+ * 
+ * A deprecated API is an API that we recommend you no longer use,
+ * due to improvements in the LDAP C SDK. While deprecated APIs are
+ * currently still implemented, they may be removed in future
+ * implementations, and we recommend using other APIs.
+ *
+ * This header file will act as a first warning before moving functions
+ * into an unsupported/deprecated state.  If your favorite application
+ * depend on any declaration and defines, and there is a good reason
+ * for not porting to new functions, Speak up now or they may disappear
+ * in a future release
+ */
+
+#ifndef _LDAP_TOBE_DEPRECATED_H
+#define _LDAP_TOBE_DEPRECATED_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * I/O function callbacks option (an API extension --
+ * LDAP_API_FEATURE_X_IO_FUNCTIONS).
+ * Use of the extended I/O functions instead is recommended
+ */
+#define LDAP_OPT_IO_FN_PTRS		0x0B	/* 11 - API extension */
+
+/*
+ * I/O callback functions (note that types for the read and write callbacks
+ * are actually in lber.h):
+ */
+typedef int	(LDAP_C LDAP_CALLBACK LDAP_IOF_SELECT_CALLBACK)( int nfds,
+	fd_set *readfds, fd_set *writefds, fd_set *errorfds,
+	struct timeval *timeout );
+typedef LBER_SOCKET (LDAP_C LDAP_CALLBACK LDAP_IOF_SOCKET_CALLBACK)(
+	int domain, int type, int protocol );
+typedef int	(LDAP_C LDAP_CALLBACK LDAP_IOF_IOCTL_CALLBACK)( LBER_SOCKET s, 
+	int option, ... );
+typedef int	(LDAP_C LDAP_CALLBACK LDAP_IOF_CONNECT_CALLBACK )(
+	LBER_SOCKET s, struct sockaddr *name, int namelen );
+typedef int	(LDAP_C LDAP_CALLBACK LDAP_IOF_CLOSE_CALLBACK )(
+	LBER_SOCKET s );
+typedef int	(LDAP_C LDAP_CALLBACK LDAP_IOF_SSL_ENABLE_CALLBACK )(
+	LBER_SOCKET s );
+
+/*
+ * Structure to hold I/O function pointers:
+ */
+struct ldap_io_fns {
+	LDAP_IOF_READ_CALLBACK *liof_read;
+	LDAP_IOF_WRITE_CALLBACK *liof_write;
+	LDAP_IOF_SELECT_CALLBACK *liof_select;
+	LDAP_IOF_SOCKET_CALLBACK *liof_socket;
+	LDAP_IOF_IOCTL_CALLBACK *liof_ioctl;
+	LDAP_IOF_CONNECT_CALLBACK *liof_connect;
+	LDAP_IOF_CLOSE_CALLBACK *liof_close;
+	LDAP_IOF_SSL_ENABLE_CALLBACK *liof_ssl_enable;
+};
+
+/*
+ * DNS resolver callbacks (an API extension --LDAP_API_FEATURE_X_DNS_FUNCTIONS).
+ * Note that gethostbyaddr() is not currently used.
+ */
+#define LDAP_OPT_DNS_FN_PTRS            0x60    /* 96 - API extension */
+
+typedef struct LDAPHostEnt {
+    char        *ldaphe_name;           /* official name of host */
+    char        **ldaphe_aliases;       /* alias list */
+    int         ldaphe_addrtype;        /* host address type */
+    int         ldaphe_length;          /* length of address */
+    char        **ldaphe_addr_list;     /* list of addresses from name server */
+} LDAPHostEnt;
+
+typedef LDAPHostEnt * (LDAP_C LDAP_CALLBACK LDAP_DNSFN_GETHOSTBYNAME)(
+        const char *name, LDAPHostEnt *result, char *buffer,
+        int buflen, int *statusp, void *extradata );
+typedef LDAPHostEnt * (LDAP_C LDAP_CALLBACK LDAP_DNSFN_GETHOSTBYADDR)(
+        const char *addr, int length, int type, LDAPHostEnt *result,
+        char *buffer, int buflen, int *statusp, void *extradata );
+typedef int (LDAP_C LDAP_CALLBACK LDAP_DNSFN_GETPEERNAME)(
+        LDAP *ld, struct sockaddr *netaddr, char *buffer, int buflen);
+
+struct ldap_dns_fns {
+        void                            *lddnsfn_extradata;
+        int                             lddnsfn_bufsize;
+        LDAP_DNSFN_GETHOSTBYNAME        *lddnsfn_gethostbyname;
+        LDAP_DNSFN_GETHOSTBYADDR        *lddnsfn_gethostbyaddr;
+	LDAP_DNSFN_GETPEERNAME          *lddnsfn_getpeername;
+};
+
+/*
+ * experimental DN format support
+ */
+LDAP_API(char **) LDAP_CALL ldap_explode_dns( const char *dn );
+LDAP_API(int) LDAP_CALL ldap_is_dns_dn( const char *dn );
+
+
+/*
+ * user friendly naming/searching routines
+ */
+typedef int (LDAP_C LDAP_CALLBACK LDAP_CANCELPROC_CALLBACK)( void *cl );
+LDAP_API(int) LDAP_CALL ldap_ufn_search_c( LDAP *ld, char *ufn,
+        char **attrs, int attrsonly, LDAPMessage **res,
+        LDAP_CANCELPROC_CALLBACK *cancelproc, void *cancelparm );
+LDAP_API(int) LDAP_CALL ldap_ufn_search_ct( LDAP *ld, char *ufn,
+        char **attrs, int attrsonly, LDAPMessage **res,
+        LDAP_CANCELPROC_CALLBACK *cancelproc, void *cancelparm,
+        char *tag1, char *tag2, char *tag3 );
+LDAP_API(int) LDAP_CALL ldap_ufn_search_s( LDAP *ld, char *ufn,
+        char **attrs, int attrsonly, LDAPMessage **res );
+LDAP_API(LDAPFiltDesc *) LDAP_CALL ldap_ufn_setfilter( LDAP *ld, char *fname );
+LDAP_API(void) LDAP_CALL ldap_ufn_setprefix( LDAP *ld, char *prefix );
+LDAP_API(int) LDAP_C ldap_ufn_timeout( void *tvparam );
+
+/*
+ * utility routines
+ */
+LDAP_API(int) LDAP_CALL ldap_charray_add( char ***a, char *s );
+LDAP_API(int) LDAP_CALL ldap_charray_merge( char ***a, char **s );
+LDAP_API(void) LDAP_CALL ldap_charray_free( char **array );
+LDAP_API(int) LDAP_CALL ldap_charray_inlist( char **a, char *s );
+LDAP_API(char **) LDAP_CALL ldap_charray_dup( char **a );
+LDAP_API(char **) LDAP_CALL ldap_str2charray( char *str, char *brkstr );
+LDAP_API(int) LDAP_CALL ldap_charray_position( char **a, char *s );
+
+/* from ldap_ssl.h - the pkcs function and declaration */
+typedef int (LDAP_C LDAP_CALLBACK LDAP_PKCS_GET_TOKEN_CALLBACK)(void *context, char **tokenname);
+typedef int (LDAP_C LDAP_CALLBACK LDAP_PKCS_GET_PIN_CALLBACK)(void *context, const char *tokenname, char **tokenpin);
+typedef int (LDAP_C LDAP_CALLBACK LDAP_PKCS_GET_CERTPATH_CALLBACK)(void *context, char **certpath);
+typedef int (LDAP_C LDAP_CALLBACK LDAP_PKCS_GET_KEYPATH_CALLBACK)(void *context,char **keypath);
+typedef int (LDAP_C LDAP_CALLBACK LDAP_PKCS_GET_MODPATH_CALLBACK)(void *context, char **modulepath);
+typedef int (LDAP_C LDAP_CALLBACK LDAP_PKCS_GET_CERTNAME_CALLBACK)(void *context, char **certname);
+typedef int (LDAP_C LDAP_CALLBACK LDAP_PKCS_GET_DONGLEFILENAME_CALLBACK)(void *context, char **filename);
+
+#define PKCS_STRUCTURE_ID 1
+struct ldapssl_pkcs_fns {
+    int local_structure_id;
+    void *local_data;
+    LDAP_PKCS_GET_CERTPATH_CALLBACK *pkcs_getcertpath;
+    LDAP_PKCS_GET_CERTNAME_CALLBACK *pkcs_getcertname;
+    LDAP_PKCS_GET_KEYPATH_CALLBACK *pkcs_getkeypath;
+    LDAP_PKCS_GET_MODPATH_CALLBACK *pkcs_getmodpath;
+    LDAP_PKCS_GET_PIN_CALLBACK *pkcs_getpin;
+    LDAP_PKCS_GET_TOKEN_CALLBACK *pkcs_gettokenname;
+    LDAP_PKCS_GET_DONGLEFILENAME_CALLBACK *pkcs_getdonglefilename;
+
+};
+
+LDAP_API(int) LDAP_CALL ldapssl_pkcs_init( const struct ldapssl_pkcs_fns *pfns);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _LDAP_TOBE_DEPRECATED_H */
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/include/ldap.h
@@ -0,0 +1,62 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+/* ldap.h - general header file for libldap */
+
+#ifndef _LDAP_H
+#define _LDAP_H
+
+/* Standard LDAP API functions and declarations */ 
+#include "ldap-standard.h"
+
+/* Extensions to the LDAP standard */
+#include "ldap-extension.h"
+
+/* A deprecated API is an API that we recommend you no longer use,
+ * due to improvements in the LDAP C SDK. While deprecated APIs are
+ * currently still implemented, they may be removed in future
+ * implementations, and we recommend using other APIs.
+ */
+
+/* Soon-to-be deprecated functions and declarations */
+#include "ldap-to-be-deprecated.h"
+
+/* Deprecated functions and declarations */
+#include "ldap-deprecated.h"
+
+#endif /* _LDAP_H */
+
new file mode 100755
--- /dev/null
+++ b/ldap/c-sdk/include/ldap_ssl.h
@@ -0,0 +1,254 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+#if !defined(LDAP_SSL_H)
+#define LDAP_SSL_H
+
+/* ldap_ssl.h - prototypes for LDAP over SSL functions */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * these three defines resolve the SSL strength 
+ * setting auth weak, diables all cert checking
+ * the CNCHECK tests for the man in the middle hack
+ */ 
+#define LDAPSSL_AUTH_WEAK       0
+#define LDAPSSL_AUTH_CERT       1
+#define LDAPSSL_AUTH_CNCHECK    2
+
+/*
+ * an ExtendedRequest [LDAPv3] specifying the OID for the
+ * Start TLS operation: RFC 2830
+ */
+#define LDAP_EXOP_START_TLS			"1.3.6.1.4.1.1466.20037"
+
+/*
+ * Initialize LDAP library for SSL
+ */
+LDAP * LDAP_CALL ldapssl_init( const char *defhost, int defport,
+	int defsecure );
+
+/*
+ * Shutdown LDAP library for SSL :
+ * Perform necessary cleanup and attempt to shutdown NSS. All existing
+ * ld session handles should be ldap_unbind(ld) prior to calling this.
+ */	
+int LDAP_CALL ldapssl_shutdown();
+
+/* Initialize LDAP library for TLS(SSL) and sends StartTLS extended
+ * operation to the Directory Server.
+ * Returns LDAP_SUCCESS if all goes well.
+ */
+int LDAP_CALL ldap_start_tls_s( LDAP *ld, LDAPControl **serverctrls,
+ 					  LDAPControl **clientctrls );
+/*
+ * Install I/O routines to make SSL over LDAP possible.
+ * Use this after ldap_init() or just use ldapssl_init() instead.
+ * Returns 0 if all goes well.
+ */
+int LDAP_CALL ldapssl_install_routines( LDAP *ld );
+
+
+/* The next four functions initialize the security code for SSL
+ * The first one ldapssl_client_init() does initialization for SSL only
+ * The next one supports server authentication using clientauth_init()
+ * and allows the caller to specify the ssl strength to use in order to
+ * verify the servers's certificate.
+ * The next one supports ldapssl_clientauth_init() intializes security 
+ * for SSL for client authentication.  The third function initializes
+ * security for doing SSL with client authentication, and PKCS, that is, 
+ * the third function initializes the security module database (secmod.db).
+ * The parameters are as follows:
+ * const char *certdbpath - path to the cert file.  This can be a shortcut 
+ *     to the directory name, if so cert7.db will be postfixed to the string.
+ * void *certdbhandle - Normally this is NULL.  This memory will need 
+ *     to be freed.
+ * int needkeydb - boolean.  Must be !=0 if client Authentification 
+ *     is required
+ * char *keydbpath - path to the key database.  This can be a shortcut 
+ *     to the directory name, if so key3.db will be postfixed to the string.
+ * void *keydbhandle - Normally this is NULL, This memory will need 
+ *     to be freed 
+ * int needsecmoddb - boolean.  Must be !=0 to assure that the correct 
+ *     security module is loaded into memory
+ * char *secmodpath - path to the secmod.  This can be a shortcut to the
+ *    directory name, if so secmod.db will be postfixed to the string.
+ *
+ *  These three functions are mutually exclusive.  You can only call 
+ *     one.  This means that, for a given process, you must call the
+ *     appropriate initialization function for the life of the process.
+ */
+
+
+/*
+ * Initialize the secure parts (Security and SSL) of the runtime for use
+ * by a client application.  This is only called once.
+ * Returns 0 if all goes well.
+ */
+
+int LDAP_CALL ldapssl_client_init(
+    const char *certdbpath, void *certdbhandle );
+
+/*
+ * Initialize the secure parts (Security and SSL) of the runtime for use
+ * by a client application using server authentication.  This is only
+ * called once.
+ *
+ * ldapssl_serverauth_init() is a server-authentication only version of
+ * ldapssl_clientauth_init().  This function allows the sslstrength
+ * to be passed in.  The sslstrength can take one of the following
+ * values:
+ *
+ *      LDAPSSL_AUTH_WEAK: indicate that you accept the server's 
+ *                         certificate without checking the CA who
+ *                         issued the certificate
+ *      LDAPSSL_AUTH_CERT: indicates that you accept the server's 
+ *                         certificate only if you trust the CA who
+ *                         issued the certificate
+ *      LDAPSSL_AUTH_CNCHECK:
+ *                         indicates that you accept the server's
+ *                         certificate only if you trust the CA who
+ *                         issued the certificate and if the value
+ *                         of the cn attribute is the DNS hostname
+ *                         of the server.  If this option is selected,
+ *			   please ensure that the "defhost" parameter
+ *			   passed to ldapssl_init() consist of only 
+ *			   one hostname and not a list of hosts.
+ *			   Furthermore, the port number must be passed
+ *			   via the "defport" parameter, and cannot
+ *			   be passed via a host:port option. 
+ *
+ * Returns 0 if all goes well.
+ */
+
+int LDAP_CALL ldapssl_serverauth_init(
+    const char *certdbpath, void *certdbhandle, const int sslstrength );
+
+/*
+ * Initialize the secure parts (Security and SSL) of the runtime for use
+ * by a client application that may want to do SSL client authentication.
+ * Returns 0 if all goes well.
+ */
+
+int LDAP_CALL ldapssl_clientauth_init( 
+    const char *certdbpath, void *certdbhandle, 
+    const int needkeydb, const char *keydbpath, void *keydbhandle );
+
+/*
+ * Initialize the secure parts (Security and SSL) of the runtime for use
+ * by a client application that may want to do SSL client authentication.
+ *
+ * Please see the description of the sslstrength value in the
+ * ldapssl_serverauth_init() function above and note the potential
+ * problems which can be caused by passing in wrong host & portname 
+ * values.  The same warning applies to the ldapssl_advclientauth_init()
+ * function.
+ *
+ * Returns 0 if all goes well.
+ */
+
+int LDAP_CALL ldapssl_advclientauth_init( 
+    const char *certdbpath, void *certdbhandle, 
+    const int needkeydb, const char *keydbpath, void *keydbhandle,  
+    const int needsecmoddb, const char *secmoddbpath, 
+    const int sslstrength );
+
+
+
+/*
+ * get a meaningful error string back from the security library
+ * this function should be called, if ldap_err2string doesn't 
+ * identify the error code.
+ */
+const char * LDAP_CALL ldapssl_err2string( const int prerrno );
+
+
+/*
+ * Enable SSL client authentication on the given ld.
+ * Returns 0 if all goes well.
+ */
+int LDAP_CALL ldapssl_enable_clientauth( LDAP *ld, char *keynickname,
+	char *keypasswd, char *certnickname );
+
+/*
+ * Set the SSL strength for an existing SSL-enabled LDAP session handle.
+ *
+ * See the description of ldapssl_serverauth_init() above for valid
+ * sslstrength values. If ld is NULL, the default for new LDAP session
+ * handles is set.
+ *
+ * Returns 0 if all goes well.
+ */ 
+int LDAP_CALL ldapssl_set_strength( LDAP *ld, int sslstrength );
+
+
+/*
+ * Set or get SSL options for an existing SSL-enabled LDAP session handle.
+ * If ld is NULL, the default options used for all future LDAP SSL sessions
+ * are the ones affected. The option values are specific to the underlying
+ * SSL provider; see ssl.h within the Network Security Services (NSS)
+ * distribution for the options supported by NSS (the default SSL provider).
+ *
+ * The ldapssl_set_option() function should be called before any LDAP
+ * connections are created.
+ *
+ * Both functions return 0 if all goes well.
+ */
+int LDAP_CALL ldapssl_set_option( LDAP *ld, int option, int on );
+int LDAP_CALL ldapssl_get_option( LDAP *ld, int option, int *onp );
+
+/*
+ * Import the file descriptor corresponding to the socket of an already
+ * open LDAP connection into SSL, and update the socket and session
+ * information accordingly. Returns 0 if all goes well.
+ */
+int LDAP_CALL ldapssl_import_fd ( LDAP *ld, int secure );
+
+/*
+ * Reset an LDAP session from SSL to a non-secure status. Basically, 
+ * this function undoes the work done by ldapssl_install_routines.
+ * Returns 0 if all goes well.
+ */
+int LDAP_CALL ldapssl_reset_to_nonsecure ( LDAP *ld );
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !defined(LDAP_SSL_H) */
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/include/ldaplog.h
@@ -0,0 +1,106 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef _LDAPLOG_H
+#define _LDAPLOG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LDAP_DEBUG_TRACE	0x00001
+#define LDAP_DEBUG_PACKETS	0x00002
+#define LDAP_DEBUG_ARGS		0x00004
+#define LDAP_DEBUG_CONNS	0x00008
+#define LDAP_DEBUG_BER		0x00010
+#define LDAP_DEBUG_FILTER	0x00020
+#define LDAP_DEBUG_CONFIG	0x00040
+#define LDAP_DEBUG_ACL		0x00080
+#define LDAP_DEBUG_STATS	0x00100
+#define LDAP_DEBUG_STATS2	0x00200
+#define LDAP_DEBUG_SHELL	0x00400
+#define LDAP_DEBUG_PARSE	0x00800
+#define LDAP_DEBUG_HOUSE        0x01000
+#define LDAP_DEBUG_REPL         0x02000
+#define LDAP_DEBUG_ANY          0x04000
+#define LDAP_DEBUG_CACHE        0x08000
+#define LDAP_DEBUG_PLUGIN	0x10000
+
+/* debugging stuff */
+/* Disable by default */
+#define LDAPDebug( level, fmt, arg1, arg2, arg3 )
+
+#ifdef LDAP_DEBUG
+#  undef LDAPDebug
+
+/* SLAPD_LOGGING should not be on for WINSOCK (16-bit Windows) */
+#  if defined(SLAPD_LOGGING)
+#    ifdef _WIN32
+       extern int	*module_ldap_debug;
+#      define LDAPDebug( level, fmt, arg1, arg2, arg3 )	\
+       { \
+		if ( *module_ldap_debug & level ) { \
+		        slapd_log_error_proc( NULL, fmt, arg1, arg2, arg3 ); \
+	    } \
+       }
+#    else /* _WIN32 */
+       extern int	ldap_debug;
+#      define LDAPDebug( level, fmt, arg1, arg2, arg3 )	\
+       { \
+		if ( ldap_debug & level ) { \
+		        slapd_log_error_proc( NULL, fmt, arg1, arg2, arg3 ); \
+	    } \
+       }
+#    endif /* Win32 */
+#  else /* no SLAPD_LOGGING */
+     extern void ber_err_print( char * );
+     extern int	ldap_debug;
+#    define LDAPDebug( level, fmt, arg1, arg2, arg3 ) \
+		if ( ldap_debug & level ) { \
+			char msg[1024]; \
+			snprintf( msg, sizeof(msg), fmt, arg1, arg2, arg3 ); \
+			msg[sizeof(msg)-1] = '\0'; \
+			ber_err_print( msg ); \
+		}
+#  endif /* SLAPD_LOGGING */
+#endif /* LDAP_DEBUG */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LDAP_H */
new file mode 100755
--- /dev/null
+++ b/ldap/c-sdk/include/ldappr.h
@@ -0,0 +1,273 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef LDAP_PR_H
+#define LDAP_PR_H
+
+#include "nspr.h"
+
+/*
+ * ldappr.h - prototypes for functions that tie libldap into NSPR (Netscape
+ *	Portable Runtime).
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Function: prldap_init().
+ *
+ * Create a new LDAP session handle, but with NSPR I/O, threading, and DNS
+ * functions installed.
+ *
+ * Pass a non-zero value for the 'shared' parameter if you plan to use
+ * this LDAP * handle from more than one thread.
+ *
+ * Returns an LDAP session handle (or NULL if an error occurs).
+ *
+ * NOTE: If you want to use IPv6, you must use prldap creating a LDAP handle
+ * with this function prldap_init.  Prldap_init installs the appropriate
+ * set of NSPR functions and prevents calling deprecated functions accidentally.
+ */
+LDAP * LDAP_CALL prldap_init( const char *defhost, int defport, int shared );
+
+
+/*
+ * Function: prldap_install_routines().
+ *
+ * Install NSPR I/O, threading, and DNS functions so they will be used by
+ * 'ld'.
+ *
+ * If 'ld' is NULL, the functions are installed as the default functions
+ * for all new LDAP * handles).
+ *
+ * Pass a non-zero value for the 'shared' parameter if you plan to use
+ * this LDAP * handle from more than one thread.
+ *
+ * Returns an LDAP API error code (LDAP_SUCCESS if all goes well).
+ */
+int LDAP_CALL prldap_install_routines( LDAP *ld, int shared );
+
+
+/*
+ * Function: prldap_set_session_option().
+ *
+ * Given an LDAP session handle or a session argument such is passed to
+ * CONNECT, POLL, NEWHANDLE, or DISPOSEHANDLE extended I/O callbacks, set
+ * an option that affects the prldap layer.
+ *
+ * If 'ld' and 'session" are both NULL, the option is set as the default
+ * for all new prldap sessions.
+ *
+ * Returns an LDAP API error code (LDAP_SUCCESS if all goes well).
+ */
+int LDAP_CALL prldap_set_session_option( LDAP *ld, void *sessionarg,
+	int option, ... );
+
+
+/*
+ * Function: prldap_get_session_option().
+ *
+ * Given an LDAP session handle or a session argument such is passed to
+ * CONNECT, POLL, NEWHANDLE, or DISPOSEHANDLE extended I/O callbacks, retrieve
+ * the setting for an option that affects the prldap layer.
+ *
+ * If 'ld' and 'session" are both NULL, the default option value for all new
+ * new prldap sessions is retrieved.
+ *
+ * Returns an LDAP API error code (LDAP_SUCCESS if all goes well).
+ */
+int LDAP_CALL prldap_get_session_option( LDAP *ld, void *sessionarg,
+	int option, ... );
+
+
+/*
+ * Available options.
+ */
+/*
+ * PRLDAP_OPT_IO_MAX_TIMEOUT: the maximum time in milliseconds to
+ * block waiting for a network I/O operation to complete.
+ *
+ * Data type: int.
+ *
+ * These two special values from ldap-extension.h can also be used;
+ *
+ *    LDAP_X_IO_TIMEOUT_NO_TIMEOUT
+ *    LDAP_X_IO_TIMEOUT_NO_WAIT
+ */
+#define PRLDAP_OPT_IO_MAX_TIMEOUT		1
+
+
+/**
+ ** Note: the types and functions below are only useful for developers
+ ** who need to layer one or more custom extended I/O functions on top of
+ ** the standard NSPR I/O functions installed by a call to prldap_init()
+ ** or prldap_install_routines().  Layering can be accomplished after
+ ** prldap_init() or prldap_install_routines() has completed successfully
+ ** by:
+ **
+ **   1) Calling ldap_get_option( ..., LDAP_X_OPT_EXTIO_FN_PTRS, ... ).
+ **
+ **   2) Saving the function pointer of one or more of the standard functions.
+ **
+ **   3) Replacing one or more standard functions in the ldap_x_ext_io_fns
+ **      struct	with new functions that optionally do some preliminary work,
+ **      call the standard function (via the function pointer saved in step 2),
+ **      and optionally do some followup work.
+ */
+
+/*
+ * Data structure for session information.
+ * seinfo_size should be set to PRLDAP_SESSIONINFO_SIZE before use.
+ */
+struct prldap_session_private;
+
+typedef struct prldap_session_info {
+	int				seinfo_size;
+	struct prldap_session_private	*seinfo_appdata;
+} PRLDAPSessionInfo;
+#define PRLDAP_SESSIONINFO_SIZE	sizeof( PRLDAPSessionInfo )
+
+
+/*
+ * Function: prldap_set_session_info().
+ *
+ * Given an LDAP session handle or a session argument such is passed to
+ * CONNECT, POLL, NEWHANDLE, or DISPOSEHANDLE extended I/O callbacks,
+ * set some application-specific data.  If ld is NULL, arg is used.  If
+ * both ld and arg are NULL, LDAP_PARAM_ERROR is returned.
+ *
+ * Returns an LDAP API error code (LDAP_SUCCESS if all goes well).
+ */
+int LDAP_CALL prldap_set_session_info( LDAP *ld, void *sessionarg,
+	PRLDAPSessionInfo *seip );
+
+
+/*
+ * Function: prldap_get_session_info().
+ *
+ * Given an LDAP session handle or a session argument such is passed to
+ * CONNECT, POLL, NEWHANDLE, or DISPOSEHANDLE extended I/O callbacks,
+ * retrieve some application-specific data.  If ld is NULL, arg is used.  If
+ * both ld and arg are NULL, LDAP_PARAM_ERROR is returned.
+ *
+ * Returns an LDAP API error code (LDAP_SUCCESS if all goes well, in
+ * which case the fields in the structure that seip points to are filled in).
+ */
+int LDAP_CALL prldap_get_session_info( LDAP *ld, void *sessionarg,
+	PRLDAPSessionInfo *seip );
+
+
+/*
+ * Data structure for socket specific information.
+ * Note: soinfo_size should be set to PRLDAP_SOCKETINFO_SIZE before use.
+ */
+struct prldap_socket_private;
+typedef struct prldap_socket_info {
+	int				soinfo_size;
+	PRFileDesc			*soinfo_prfd;
+	struct prldap_socket_private	*soinfo_appdata;
+} PRLDAPSocketInfo;
+#define PRLDAP_SOCKETINFO_SIZE	sizeof( PRLDAPSocketInfo )
+
+
+/*
+ * Function: prldap_set_socket_info().
+ *
+ * Given an integer fd and a socket argument such as those passed to the
+ * extended I/O callback functions, set socket specific information.
+ *
+ * Returns an LDAP API error code (LDAP_SUCCESS if all goes well).
+ *
+ * Note: it is only safe to change soinfo_prfd from within the CONNECT
+ * extended I/O callback function.
+ */
+int LDAP_CALL prldap_set_socket_info( int fd, void *socketarg,
+					PRLDAPSocketInfo *soip );
+
+/*
+ * Function: prldap_get_socket_info().
+ *
+ * Given an integer fd and a socket argument such as those passed to the
+ * extended I/O callback functions, retrieve socket specific information.
+ *
+ * Returns an LDAP API error code (LDAP_SUCCESS if all goes well, in
+ * which case the fields in the structure that soip points to are filled in).
+ */
+int LDAP_CALL prldap_get_socket_info( int fd, void *socketarg,
+					PRLDAPSocketInfo *soip );
+
+/*
+ * Function: prldap_get_default_socket_info().
+ *
+ * Given an LDAP session handle, retrieve socket specific information.
+ * If ld is NULL, LDAP_PARAM_ERROR is returned.
+ *
+ * Returns an LDAP API error code (LDAP_SUCCESS if all goes well, in
+ * which case the fields in the structure that soip points to are filled in).
+ */
+int LDAP_CALL prldap_get_default_socket_info( LDAP *ld, PRLDAPSocketInfo *soip );
+
+/*
+ * Function: prldap_set_default_socket_info().
+ *
+ * Given an LDAP session handle, set socket specific information.
+ * If ld is NULL, LDAP_PARAM_ERROR is returned.
+ *
+ * Returns an LDAP API error code (LDAP_SUCCESS if all goes well, in
+ * which case the fields in the structure that soip points to are filled in).
+ */
+int LDAP_CALL prldap_set_default_socket_info( LDAP *ld, PRLDAPSocketInfo *soip );
+
+/* Function: prldap_is_installed()
+ * Check if NSPR routine is installed 
+ */
+PRBool prldap_is_installed( LDAP *ld );
+
+/* Function: prldap_import_connection().
+ * Given a ldap handle with connection already done with ldap_init()
+ * installs NSPR routines and imports the original connection info.
+ *
+ * Returns an LDAP API error code (LDAP_SUCCESS if all goes well).
+ */
+int LDAP_CALL prldap_import_connection (LDAP *ld);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !defined(LDAP_PR_H) */
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/include/ldaprot.h
@@ -0,0 +1,203 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef _LDAPROT_H
+#define _LDAPROT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LDAP_VERSION1	1
+#define LDAP_VERSION2	2
+#define LDAP_VERSION3	3
+#define LDAP_VERSION	LDAP_VERSION3
+
+#define COMPAT20
+#define COMPAT30
+#if defined(COMPAT20) || defined(COMPAT30)
+#define COMPAT
+#endif
+
+#define LDAP_URL_PREFIX		"ldap://"
+#define LDAP_URL_PREFIX_LEN	7
+#define LDAPS_URL_PREFIX	"ldaps://"
+#define LDAPS_URL_PREFIX_LEN	8
+#define LDAP_REF_STR		"Referral:\n"
+#define LDAP_REF_STR_LEN	10
+
+/* 
+ * specific LDAP instantiations of BER types we know about
+ */
+
+/* general stuff */
+#define LDAP_TAG_MESSAGE	0x30L	/* tag is 16 + constructed bit */
+#define OLD_LDAP_TAG_MESSAGE	0x10L	/* forgot the constructed bit  */
+#define LDAP_TAG_MSGID		0x02L   /* INTEGER */
+#define LDAP_TAG_LDAPDN		0x04L	/* OCTET STRING */
+#define LDAP_TAG_CONTROLS	0xa0L	/* context specific + constructed + 0 */
+#define LDAP_TAG_REFERRAL	0xa3L	/* context specific + constructed + 3 */
+#define LDAP_TAG_NEWSUPERIOR	0x80L	/* context specific + primitive + 0 */
+#define LDAP_TAG_MRA_OID	0x81L	/* context specific + primitive + 1 */
+#define LDAP_TAG_MRA_TYPE	0x82L	/* context specific + primitive + 2 */
+#define LDAP_TAG_MRA_VALUE	0x83L	/* context specific + primitive + 3 */
+#define LDAP_TAG_MRA_DNATTRS	0x84L	/* context specific + primitive + 4 */
+#define LDAP_TAG_EXOP_REQ_OID	0x80L	/* context specific + primitive + 0 */
+#define LDAP_TAG_EXOP_REQ_VALUE	0x81L	/* context specific + primitive + 1 */
+#define LDAP_TAG_EXOP_RES_OID	0x8aL	/* context specific + primitive + 10 */
+#define LDAP_TAG_EXOP_RES_VALUE	0x8bL	/* context specific + primitive + 11 */
+#define LDAP_TAG_SK_MATCHRULE   0x80L   /* context specific + primitive + 0 */
+#define LDAP_TAG_SK_REVERSE 	0x81L	/* context specific + primitive + 1 */
+#define LDAP_TAG_SR_ATTRTYPE    0x80L   /* context specific + primitive + 0 */
+#define LDAP_TAG_SASL_RES_CREDS	0x87L	/* context specific + primitive + 7 */
+#define LDAP_TAG_VLV_BY_INDEX	0xa0L	/* context specific + constructed + 0 */
+#define LDAP_TAG_VLV_BY_VALUE	0x81L	/* context specific + primitive + 1 */
+#define LDAP_TAG_PWP_WARNING	0xA0L   /* context specific + constructed */
+#define LDAP_TAG_PWP_SECSLEFT	0x80L   /* context specific + primitive */
+#define LDAP_TAG_PWP_GRCLOGINS	0x81L   /* context specific + primitive + 1 */
+#define LDAP_TAG_PWP_ERROR	0x81L   /* context specific + primitive + 1 */
+#define LDAP_TAG_PWDMOD_REQ_ID  0x80L   /* context specific + primitive + 0 */
+#define LDAP_TAG_PWDMOD_REQ_OLD 0x81L   /* context specific + primitive + 1 */
+#define LDAP_TAG_PWDMOD_REQ_NEW 0x82L   /* context specific + primitive + 2 */
+#define LDAP_TAG_PWDMOD_RES_GEN 0x80L   /* context specific + primitive + 0 */
+
+/* possible operations a client can invoke */
+#define LDAP_REQ_BIND		0x60L	/* application + constructed + 0 */
+#define LDAP_REQ_UNBIND		0x42L	/* application + primitive   + 2 */
+#define LDAP_REQ_SEARCH		0x63L	/* application + constructed + 3 */
+#define LDAP_REQ_MODIFY		0x66L	/* application + constructed + 6 */
+#define LDAP_REQ_ADD		0x68L	/* application + constructed + 8 */
+#define LDAP_REQ_DELETE		0x4aL	/* application + primitive   + 10 */
+#define LDAP_REQ_MODRDN		0x6cL	/* application + constructed + 12 */
+#define LDAP_REQ_MODDN		0x6cL	/* application + constructed + 12 */
+#define LDAP_REQ_RENAME		0x6cL	/* application + constructed + 12 */
+#define LDAP_REQ_COMPARE	0x6eL	/* application + constructed + 14 */
+#define LDAP_REQ_ABANDON	0x50L	/* application + primitive   + 16 */
+#define LDAP_REQ_EXTENDED	0x77L	/* application + constructed + 23 */
+
+/* U-M LDAP release 3.0 compatibility stuff */
+#define LDAP_REQ_UNBIND_30	0x62L
+#define LDAP_REQ_DELETE_30	0x6aL
+#define LDAP_REQ_ABANDON_30	0x70L
+
+/*
+ * old broken stuff for backwards compatibility - forgot application tag
+ * and constructed/primitive bit
+ */
+#define OLD_LDAP_REQ_BIND	0x00L
+#define OLD_LDAP_REQ_UNBIND	0x02L
+#define OLD_LDAP_REQ_SEARCH	0x03L
+#define OLD_LDAP_REQ_MODIFY	0x06L
+#define OLD_LDAP_REQ_ADD	0x08L
+#define OLD_LDAP_REQ_DELETE	0x0aL
+#define OLD_LDAP_REQ_MODRDN	0x0cL
+#define OLD_LDAP_REQ_MODDN	0x0cL
+#define OLD_LDAP_REQ_COMPARE	0x0eL
+#define OLD_LDAP_REQ_ABANDON	0x10L
+
+/* old broken stuff for backwards compatibility */
+#define OLD_LDAP_RES_BIND		0x01L
+#define OLD_LDAP_RES_SEARCH_ENTRY	0x04L
+#define OLD_LDAP_RES_SEARCH_RESULT	0x05L
+#define OLD_LDAP_RES_MODIFY		0x07L
+#define OLD_LDAP_RES_ADD		0x09L
+#define OLD_LDAP_RES_DELETE		0x0bL
+#define OLD_LDAP_RES_MODRDN		0x0dL
+#define OLD_LDAP_RES_MODDN		0x0dL
+#define OLD_LDAP_RES_COMPARE		0x0fL
+
+/* U-M LDAP 3.0 compatibility auth methods */
+#define LDAP_AUTH_SIMPLE_30	0xa0L	/* context specific + constructed */
+#define LDAP_AUTH_KRBV41_30	0xa1L	/* context specific + constructed */
+#define LDAP_AUTH_KRBV42_30	0xa2L	/* context specific + constructed */
+
+/* old broken stuff */
+#define OLD_LDAP_AUTH_SIMPLE	0x00L
+#define OLD_LDAP_AUTH_KRBV4	0x01L
+#define OLD_LDAP_AUTH_KRBV42	0x02L
+
+/* U-M LDAP 3.0 compatibility filter types */
+#define LDAP_FILTER_PRESENT_30	0xa7L	/* context specific + constructed */
+
+/* filter types */
+#define LDAP_FILTER_AND		0xa0L	/* context specific + constructed + 0 */
+#define LDAP_FILTER_OR		0xa1L	/* context specific + constructed + 1 */
+#define LDAP_FILTER_NOT		0xa2L	/* context specific + constructed + 2 */
+#define LDAP_FILTER_EQUALITY	0xa3L	/* context specific + constructed + 3 */
+#define LDAP_FILTER_SUBSTRINGS	0xa4L	/* context specific + constructed + 4 */
+#define LDAP_FILTER_GE		0xa5L	/* context specific + constructed + 5 */
+#define LDAP_FILTER_LE		0xa6L	/* context specific + constructed + 6 */
+#define LDAP_FILTER_PRESENT	0x87L	/* context specific + primitive   + 7 */
+#define LDAP_FILTER_APPROX	0xa8L	/* context specific + constructed + 8 */
+#define LDAP_FILTER_EXTENDED	0xa9L	/* context specific + constructed + 0 */
+
+/* old broken stuff */
+#define OLD_LDAP_FILTER_AND		0x00L
+#define OLD_LDAP_FILTER_OR		0x01L
+#define OLD_LDAP_FILTER_NOT		0x02L
+#define OLD_LDAP_FILTER_EQUALITY	0x03L
+#define OLD_LDAP_FILTER_SUBSTRINGS	0x04L
+#define OLD_LDAP_FILTER_GE		0x05L
+#define OLD_LDAP_FILTER_LE		0x06L
+#define OLD_LDAP_FILTER_PRESENT		0x07L
+#define OLD_LDAP_FILTER_APPROX		0x08L
+
+/* substring filter component types */
+#define LDAP_SUBSTRING_INITIAL	0x80L	/* context specific + primitive + 0 */
+#define LDAP_SUBSTRING_ANY	0x81L	/* context specific + primitive + 1 */
+#define LDAP_SUBSTRING_FINAL	0x82L	/* context specific + primitive + 2 */
+
+/* extended filter component types */
+#define LDAP_FILTER_EXTENDED_OID	0x81L	/* context spec. + prim. + 1 */
+#define LDAP_FILTER_EXTENDED_TYPE	0x82L	/* context spec. + prim. + 2 */
+#define LDAP_FILTER_EXTENDED_VALUE	0x83L	/* context spec. + prim. + 3 */
+#define LDAP_FILTER_EXTENDED_DNATTRS	0x84L	/* context spec. + prim. + 4 */
+
+/* U-M LDAP 3.0 compatibility substring filter component types */
+#define LDAP_SUBSTRING_INITIAL_30	0xa0L	/* context specific */
+#define LDAP_SUBSTRING_ANY_30		0xa1L	/* context specific */
+#define LDAP_SUBSTRING_FINAL_30		0xa2L	/* context specific */
+
+/* old broken stuff */
+#define OLD_LDAP_SUBSTRING_INITIAL	0x00L
+#define OLD_LDAP_SUBSTRING_ANY		0x01L
+#define OLD_LDAP_SUBSTRING_FINAL	0x02L
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _LDAPROT_H */
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/include/ldif.h
@@ -0,0 +1,114 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Copyright (c) 1996 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+/* NOTE: As of mozldap version 6.0.1 the LDIF functions are now
+   publicly usable.  The LDIF functions were originally designed for
+   "internal use only" purposes and as such the APIs are not very modern
+   or safe.  For example, the caller needs to be careful to provide
+   adequately sized buffers and so on.
+*/
+
+#ifndef _LDIF_H
+#define _LDIF_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LDIF_VERSION_ONE        1	/* LDIF standard version */
+
+#define LDIF_MAX_LINE_WIDTH      76      /* maximum length of LDIF lines */
+
+/*
+ * Macro to calculate maximum number of bytes that the base64 equivalent
+ * of an item that is "vlen" bytes long will take up.  Base64 encoding
+ * uses one byte for every six bits in the value plus up to two pad bytes.
+ */
+#define LDIF_BASE64_LEN(vlen)	(((vlen) * 4 / 3 ) + 3)
+
+/*
+ * Macro to calculate maximum size that an LDIF-encoded type (length
+ * tlen) and value (length vlen) will take up:  room for type + ":: " +
+ * first newline + base64 value + continued lines.  Each continued line
+ * needs room for a newline and a leading space character.
+ */
+#define LDIF_SIZE_NEEDED(tlen,vlen) \
+    ((tlen) + 4 + LDIF_BASE64_LEN(vlen) \
+    + ((LDIF_BASE64_LEN(vlen) + tlen + 3) / LDIF_MAX_LINE_WIDTH * 2 ))
+
+/*
+ * Options for ldif_put_type_and_value_with_options() and 
+ * ldif_type_and_value_with_options().
+ */
+#define LDIF_OPT_NOWRAP			0x01UL
+#define LDIF_OPT_VALUE_IS_URL		0x02UL
+#define LDIF_OPT_MINIMAL_ENCODING	0x04UL
+
+int ldif_parse_line( char *line, char **type, char **value, int *vlen);
+char * ldif_getline( char **next );
+void ldif_put_type_and_value( char **out, char *t, char *val, int vlen );
+void ldif_put_type_and_value_nowrap( char **out, char *t, char *val, int vlen );
+void ldif_put_type_and_value_with_options( char **out, char *t, char *val,
+	int vlen, unsigned long options );
+char *ldif_type_and_value( char *type, char *val, int vlen );
+char *ldif_type_and_value_nowrap( char *type, char *val, int vlen );
+char *ldif_type_and_value_with_options( char *type, char *val, int vlen,
+	unsigned long options );
+int ldif_base64_decode( char *src, unsigned char *dst );
+int ldif_base64_encode( unsigned char *src, char *dst, int srclen,
+	int lenused );
+int ldif_base64_encode_nowrap( unsigned char *src, char *dst, int srclen,
+	int lenused );
+char *ldif_get_entry( FILE *fp, int *lineno );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LDIF_H */
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/include/portable.h
@@ -0,0 +1,468 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Copyright (c) 1994 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+#ifndef _PORTABLE_H
+#define _PORTABLE_H
+
+/*
+ * portable.h for LDAP -- this is where we define common stuff to make
+ * life easier on various Unix systems.
+ *
+ * Unless you are porting LDAP to a new platform, you should not need to
+ * edit this file.
+ */
+
+#ifndef SYSV
+#if defined( hpux ) || defined( SOLARIS ) || defined ( sgi ) || defined( SVR4 )
+#define SYSV
+#endif
+#endif
+
+/*
+ * under System V, use sysconf() instead of getdtablesize
+ */
+#if !defined( USE_SYSCONF ) && defined( SYSV )
+#define USE_SYSCONF
+#endif
+
+/*
+ * under System V, daemons should use setsid() instead of detaching from their
+ * tty themselves
+ */
+#if !defined( USE_SETSID ) && defined( SYSV )
+#define USE_SETSID
+#endif
+
+/*
+ * System V has socket options in filio.h
+ */
+#if !defined( NEED_FILIO ) && defined( SYSV ) && !defined( hpux ) && !defined( AIX )
+#define NEED_FILIO
+#endif
+
+/*
+ * use lockf() under System V
+ */
+#if !defined( USE_LOCKF ) && ( defined( SYSV ) || defined( aix ))
+#define USE_LOCKF
+#endif
+
+/*
+ * on many systems, we should use waitpid() instead of waitN()
+ */
+#if !defined( USE_WAITPID ) && ( defined( SYSV ) || defined( sunos4 ) || defined( ultrix ) || defined( aix ))
+#define USE_WAITPID
+#endif
+
+/*
+ * define the wait status argument type
+ */
+#if ( defined( SunOS ) && SunOS < 40 ) || defined( nextstep )
+#define WAITSTATUSTYPE	union wait
+#else
+#define WAITSTATUSTYPE	int
+#endif
+
+/*
+ * defined the options for openlog (syslog)
+ */
+#ifdef ultrix
+#define OPENLOG_OPTIONS		LOG_PID
+#else
+#define OPENLOG_OPTIONS		( LOG_PID | LOG_NOWAIT )
+#endif
+
+/*
+ * some systems don't have the BSD re_comp and re_exec routines
+ */
+#ifndef NEED_BSDREGEX
+#if ( defined( SYSV ) || defined( NETBSD ) || defined( FREEBSD ) || defined(__OpenBSD__) || defined( linux ) || defined( DARWIN )) && !defined(sgi)
+#define NEED_BSDREGEX
+#endif
+#endif
+
+/*
+ * many systems do not have the setpwfile() library routine... we just
+ * enable use for those systems we know have it.
+ */
+#ifndef HAVE_SETPWFILE
+#if defined( sunos4 ) || defined( ultrix ) || defined( OSF1 )
+#define HAVE_SETPWFILE
+#endif
+#endif
+
+/*
+ * Are sys_errlist and sys_nerr declared in stdio.h?
+ */
+#ifndef SYSERRLIST_IN_STDIO
+#if defined( freebsd ) 
+#define SYSERRLIST_IN_STDIO
+#endif
+#endif
+
+
+/*
+ * Is snprintf() part of the standard C runtime library?
+ */
+#if !defined(HAVE_SNPRINTF)
+#if defined(SOLARIS) || defined(LINUX) || defined(HPUX) || defined(AIX)
+#define HAVE_SNPRINTF
+#endif
+#if defined(_WINDOWS)
+#define snprintf _snprintf
+#define HAVE_SNPRINTF
+#endif
+#endif
+
+
+/*
+ * Async IO.  Use a non blocking implementation of connect() and 
+ * dns functions
+ */
+#if !defined(LDAP_ASYNC_IO)
+#if !defined(_WINDOWS) && !defined(macintosh)
+#define LDAP_ASYNC_IO
+#endif /* _WINDOWS */
+#endif
+
+/*
+ * for select()
+ */
+#if !defined(WINSOCK) && !defined(_WINDOWS) && !defined(macintosh) && !defined(XP_OS2)
+#if defined(hpux) || defined(LINUX) || defined(SUNOS4) || defined(XP_BEOS)
+#include <sys/time.h>
+#else
+#include <sys/select.h>
+#endif
+#if !defined(FD_SET)
+#define NFDBITS         32
+#define FD_SETSIZE      32
+#define FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
+#define FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
+#define FD_ISSET(n, p)  ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
+#define FD_ZERO(p)      bzero((char *)(p), sizeof(*(p)))
+#endif /* !FD_SET */
+#endif /* !WINSOCK && !_WINDOWS && !macintosh */
+
+
+/*
+ * for connect() -- must we block signals when calling connect()?  This
+ * is necessary on some buggy UNIXes.
+ */
+#if !defined(NSLDAPI_CONNECT_MUST_NOT_BE_INTERRUPTED) && \
+	( defined(AIX) || defined(IRIX) || defined(HPUX) || defined(SUNOS4) \
+	|| defined(SOLARIS) || defined(OSF1) ||defined(freebsd)) 
+#define NSLDAPI_CONNECT_MUST_NOT_BE_INTERRUPTED
+#endif
+
+/*
+ * On most platforms, sigprocmask() works fine even in multithreaded code.
+ * But not everywhere.
+ */
+#ifdef AIX
+#define NSLDAPI_MT_SAFE_SIGPROCMASK(h,s,o)	sigthreadmask(h,s,o)
+#else
+#define NSLDAPI_MT_SAFE_SIGPROCMASK(h,s,o)	sigprocmask(h,s,o)
+#endif
+
+/*
+ * toupper and tolower macros are different under bsd and sys v
+ */
+#if defined( SYSV ) && !defined( hpux )
+#define TOUPPER(c)	(isascii(c) && islower(c) ? _toupper(c) : c)
+#define TOLOWER(c)	(isascii(c) && isupper(c) ? _tolower(c) : c)
+#else
+#define TOUPPER(c)	(isascii(c) && islower(c) ? toupper(c) : c)
+#define TOLOWER(c)	(isascii(c) && isupper(c) ? tolower(c) : c)
+#endif
+
+/*
+ * put a cover on the tty-related ioctl calls we need to use
+ */
+#if defined( NeXT ) || (defined(SunOS) && SunOS < 40)
+#define TERMIO_TYPE struct sgttyb
+#define TERMFLAG_TYPE int
+#define GETATTR( fd, tiop )	ioctl((fd), TIOCGETP, (caddr_t)(tiop))
+#define SETATTR( fd, tiop )	ioctl((fd), TIOCSETP, (caddr_t)(tiop))
+#define GETFLAGS( tio )		(tio).sg_flags
+#define SETFLAGS( tio, flags )	(tio).sg_flags = (flags)
+#else
+#define USE_TERMIOS
+#define TERMIO_TYPE struct termios
+#define TERMFLAG_TYPE tcflag_t
+#define GETATTR( fd, tiop )	tcgetattr((fd), (tiop))
+#define SETATTR( fd, tiop )	tcsetattr((fd), TCSANOW /* 0 */, (tiop))
+#define GETFLAGS( tio )		(tio).c_lflag
+#define SETFLAGS( tio, flags )	(tio).c_lflag = (flags)
+#endif
+
+#if ( !defined( HPUX9 )) && ( !defined( sunos4 )) && ( !defined( SNI )) && \
+	( !defined( HAVE_TIME_R ))
+#define HAVE_TIME_R
+#endif
+
+#if defined(SNI) || defined(LINUX1_2)
+int strcasecmp(const char *, const char *);
+#ifdef SNI
+int strncasecmp(const char *, const char *, int);
+#endif /* SNI */
+#ifdef LINUX1_2
+int strncasecmp(const char *, const char *, size_t);
+#endif /* LINUX1_2 */
+#endif /* SNI || LINUX1_2 */
+
+#if defined(_WINDOWS) || defined(macintosh) || defined(XP_OS2) || defined(DARWIN)
+#define GETHOSTBYNAME( n, r, b, l, e )  gethostbyname( n )
+#define NSLDAPI_CTIME( c, b, l )	ctime( c )
+#define STRTOK( s1, s2, l )		strtok( s1, s2 )
+#elif defined(XP_BEOS)
+#define GETHOSTBYNAME( n, r, b, l, e )  gethostbyname( n )
+#define NSLDAPI_CTIME( c, b, l )                ctime_r( c, b )
+#define STRTOK( s1, s2, l )		strtok_r( s1, s2, l )
+#define HAVE_STRTOK_R
+#else /* UNIX */
+#if (defined(AIX) && defined(_THREAD_SAFE)) || defined(OSF1)
+#define NSLDAPI_NETDB_BUF_SIZE	 sizeof(struct protoent_data) 
+#else
+#define NSLDAPI_NETDB_BUF_SIZE	1024
+#endif
+
+#if defined(sgi) || defined(HPUX9) || defined(SCOOS) || \
+    defined(UNIXWARE) || defined(SUNOS4) || defined(SNI) || defined(BSDI) || \
+    defined(NCR) || defined(OSF1) || defined(NEC) || defined(VMS) || \
+    ( defined(HPUX10) && !defined(_REENTRANT)) || defined(HPUX11) || \
+    defined(UnixWare) || defined(NETBSD) || \
+    defined(FREEBSD) || defined(OPENBSD) || \
+    (defined(LINUX) && __GLIBC__ < 2) || \
+    (defined(AIX) && !defined(USE_REENTRANT_LIBC))
+#define GETHOSTBYNAME( n, r, b, l, e )  gethostbyname( n )
+#elif defined(AIX)
+/* Maybe this is for another version of AIX?
+   Commenting out for AIX 4.1 for Nova
+   Replaced with following to lines, stolen from the #else below
+#define GETHOSTBYNAME_BUF_T struct hostent_data
+*/
+typedef char GETHOSTBYNAME_buf_t [NSLDAPI_NETDB_BUF_SIZE];
+#define GETHOSTBYNAME_BUF_T GETHOSTBYNAME_buf_t
+#define GETHOSTBYNAME( n, r, b, l, e ) \
+	(memset (&b, 0, l), gethostbyname_r (n, r, &b) ? NULL : r)
+#elif defined(HPUX10)
+#define GETHOSTBYNAME_BUF_T struct hostent_data
+#define GETHOSTBYNAME( n, r, b, l, e )	nsldapi_compat_gethostbyname_r( n, r, (char *)&b, l, e )
+#elif defined(LINUX) || defined(DRAGONFLY)
+typedef char GETHOSTBYNAME_buf_t [NSLDAPI_NETDB_BUF_SIZE];
+#define GETHOSTBYNAME_BUF_T GETHOSTBYNAME_buf_t
+#define GETHOSTBYNAME( n, r, b, l, rp, e )  gethostbyname_r( n, r, b, l, rp, e )
+#define GETHOSTBYNAME_R_RETURNS_INT
+#else
+typedef char GETHOSTBYNAME_buf_t [NSLDAPI_NETDB_BUF_SIZE];
+#define GETHOSTBYNAME_BUF_T GETHOSTBYNAME_buf_t
+#define GETHOSTBYNAME( n, r, b, l, e )  gethostbyname_r( n, r, b, l, e )
+#endif
+#if defined(HPUX9) || defined(LINUX1_2) || defined(LINUX2_0) || \
+    defined(LINUX2_1) || defined(SUNOS4) || defined(SNI) || \
+    defined(SCOOS) || defined(BSDI) || defined(NCR) || \
+    defined(NEC) || ( defined(HPUX10) && !defined(_REENTRANT)) || \
+    (defined(AIX) && !defined(USE_REENTRANT_LIBC))
+#define NSLDAPI_CTIME( c, b, l )	ctime( c )
+#elif defined(HPUX10) && defined(_REENTRANT) && !defined(HPUX11)
+#define NSLDAPI_CTIME( c, b, l )	nsldapi_compat_ctime_r( c, b, l )
+#elif defined( IRIX6_2 ) || defined( IRIX6_3 ) || defined(UNIXWARE) \
+	|| defined(OSF1V4) || defined(AIX) || defined(UnixWare) \
+        || defined(hpux) || defined(HPUX11) || defined(NETBSD) \
+        || defined(IRIX6) || defined(FREEBSD) || defined(VMS) \
+        || defined(NTO) || defined(OPENBSD) || defined(DRAGONFLY)
+#define NSLDAPI_CTIME( c, b, l )        ctime_r( c, b )
+#elif defined( OSF1V3 )
+#define NSLDAPI_CTIME( c, b, l )	(ctime_r( c, b, l ) ? NULL : b)
+#else
+#define NSLDAPI_CTIME( c, b, l )	ctime_r( c, b, l )
+#endif
+#if defined(hpux9) || defined(SUNOS4) || defined(SNI) || \
+    defined(SCOOS) || defined(BSDI) || defined(NCR) || defined(VMS) || \
+    defined(NEC) || (defined(LINUX) && __GNU_LIBRARY__ != 6) || \
+    (defined(AIX) && !defined(USE_REENTRANT_LIBC))
+#define STRTOK( s1, s2, l )		strtok( s1, s2 )
+#else
+#define HAVE_STRTOK_R
+#ifndef strtok_r
+char *strtok_r(char *, const char *, char **);
+#endif
+#define STRTOK( s1, s2, l )		(char *)strtok_r( s1, s2, l )
+#endif /* STRTOK */
+#endif /* UNIX */
+
+#if defined( ultrix ) || defined( nextstep )
+extern char *strdup();
+#endif /* ultrix || nextstep */
+
+#if defined( sunos4 ) || defined( OSF1 )
+#define	BSD_TIME	1	/* for servers/slapd/log.h */
+#endif /* sunos4 || osf */
+
+#if defined(XP_OS2)
+#include <machine/endian.h>   /* for htonl, et.al. */
+#include <arpa/inet.h>	      /* for inet_addr() */
+#elif !defined(_WINDOWS) && !defined(macintosh)
+#include <netinet/in.h>
+#if !defined(XP_BEOS)
+#include <arpa/inet.h>	/* for inet_addr() */
+#endif
+#endif
+
+
+/*
+ * Define portable 32-bit integral types.
+ */
+#include <limits.h>
+#if UINT_MAX >= 0xffffffffU	/* an int holds at least 32 bits */
+    typedef signed int nsldapi_int_32;
+    typedef unsigned int nsldapi_uint_32;
+#else				/* ints are < 32 bits; use long instead */
+    typedef signed long nsldapi_int_32;
+    typedef unsigned long nsldapi_uint_32;
+#endif
+
+/*
+ * Define a portable type for IPv4 style Internet addresses (32 bits):
+ */
+#if defined(_IN_ADDR_T) || defined(aix) || defined(HPUX11) || defined(OSF1)
+typedef in_addr_t	nsldapi_in_addr_t;
+#else
+typedef nsldapi_uint_32	nsldapi_in_addr_t;
+#endif
+
+#ifdef SUNOS4
+#include <pcfs/pc_dir.h>	/* for toupper() */
+int fprintf(FILE *, char *, ...);
+int fseek(FILE *, long, int);
+int fread(char *, int, int, FILE *);
+int fclose(FILE *);
+int fflush(FILE *);
+int rewind(FILE *);
+void *memmove(void *, const void *, size_t);
+int strcasecmp(char *, char *);
+int strncasecmp(char *, char *, int);
+time_t time(time_t *);
+void perror(char *);
+int fputc(char, FILE *);
+int fputs(char *, FILE *);
+int re_exec(char *);
+int socket(int, int, int);
+void bzero(char *, int);
+unsigned long inet_addr(char *);
+char * inet_ntoa(struct in_addr);
+int getdtablesize();
+int connect(int, struct sockaddr *, int);
+#endif /* SUNOS4 */
+
+/* #if defined(SUNOS4) || defined(SNI) */
+#if defined(SUNOS4)
+int select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
+#endif /* SUNOS4 || SNI */
+
+/*
+ * SAFEMEMCPY is an overlap-safe copy from s to d of n bytes
+ */
+#ifdef macintosh
+#define SAFEMEMCPY( d, s, n )	BlockMoveData( (Ptr)s, (Ptr)d, n )
+#else /* macintosh */
+#ifdef sunos4
+#define SAFEMEMCPY( d, s, n )	bcopy( s, d, n )
+#else /* sunos4 */
+#define SAFEMEMCPY( d, s, n )	memmove( d, s, n )
+#endif /* sunos4 */
+#endif /* macintosh */
+
+#ifdef _WINDOWS
+
+#define strcasecmp strcmpi
+#define strncasecmp _strnicmp
+#define bzero(a, b) memset( a, 0, b )
+#define getpid _getpid
+#define ioctl ioctlsocket
+#define sleep(a) Sleep( a*1000 )
+
+#define EMSGSIZE WSAEMSGSIZE
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#define EHOSTUNREACH WSAEHOSTUNREACH
+
+#ifndef MAXPATHLEN
+#define MAXPATHLEN _MAX_PATH
+#endif
+
+/* We'd like this number to be prime for the hash
+ * into the Connection table */
+#define DS_MAX_NT_SOCKET_CONNECTIONS 2003
+
+#elif defined(XP_OS2)
+
+#define strcasecmp stricmp
+#define strncasecmp strnicmp
+#define bzero(a, b) memset( a, 0, b )
+#include <string.h> /*for strcmpi()*/
+#include <time.h>   /*for ctime()*/
+
+#endif /* XP_OS2 */
+
+/* Define a macro to support large files */
+#ifdef _LARGEFILE64_SOURCE
+#define NSLDAPI_FOPEN( filename, mode )	fopen64( filename, mode )
+#else
+#define NSLDAPI_FOPEN( filename, mode )	fopen( filename, mode )
+#endif
+
+#if defined(LINUX) || defined(AIX) || defined(HPUX) || defined(_WINDOWS)
+size_t nsldapi_compat_strlcpy(char *dst, const char *src, size_t len);
+#define STRLCPY nsldapi_compat_strlcpy
+#else
+#define STRLCPY strlcpy
+#endif
+
+#endif /* _PORTABLE_H */
new file mode 100755
--- /dev/null
+++ b/ldap/c-sdk/include/proto-ntutil.h
@@ -0,0 +1,99 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+/******************************************************
+ *
+ *  proto-ntutil.h - Prototypes for utility functions used
+ *  throughout slapd on NT.
+ *
+ ******************************************************/
+#if defined( _WINDOWS )
+
+#ifndef _PROTO_NTUTIL
+#define _PROTO_NTUTIL
+
+/* 
+ *
+ * ntreg.c  
+ *
+ */
+extern int SlapdGetRegSZ( LPTSTR lpszRegKey, LPSTR lpszValueName, LPTSTR lpszValue );
+
+/* 
+ *
+ * getopt.c  
+ *
+ */
+extern int getopt (int argc, char *const *argv, const char *optstring);
+
+/* 
+ *
+ * ntevent.c  
+ *
+ */
+extern BOOL MultipleInstances();
+extern BOOL SlapdIsAService();
+extern void InitializeSlapdLogging( LPTSTR lpszRegLocation, LPTSTR lpszEventLogName, LPTSTR lpszMessageFile );
+extern void ReportSlapdEvent(WORD wEventType, DWORD dwIdEvent, WORD wNumInsertStrings, 
+						char *pszStrings);
+extern BOOL ReportSlapdStatusToSCMgr(
+					SERVICE_STATUS *serviceStatus,
+					SERVICE_STATUS_HANDLE serviceStatusHandle,
+					HANDLE Event,
+					DWORD dwCurrentState,
+                    DWORD dwWin32ExitCode,
+                    DWORD dwCheckPoint,
+                    DWORD dwWaitHint);
+extern void WINAPI SlapdServiceCtrlHandler(DWORD dwOpcode);
+extern BOOL SlapdGetServerNameFromCmdline(char *szServerName, char *szCmdLine);
+
+/* 
+ *
+ * ntgetpassword.c  
+ *
+ */
+#ifdef NET_SSL
+extern char *Slapd_GetPassword();
+#ifdef FORTEZZA
+extern char *Slapd_GetFortezzaPIN();
+#endif
+extern void CenterDialog(HWND hwndParent, HWND hwndDialog);
+#endif /* NET_SSL */
+
+#endif /* _PROTO_NTUTIL */
+
+#endif /* _WINDOWS */
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/include/regex.h
@@ -0,0 +1,95 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+#if defined( macintosh ) || defined( DOS ) || defined( _WINDOWS ) || defined( NEED_BSDREGEX ) || defined( XP_OS2 )
+/*
+ * Copyright (c) 1993 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+/*
+ * regex.h -- includes for regular expression matching routines
+ * 13 August 1993 Mark C Smith
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ldap.h" 
+
+#if !defined( NEEDPROTOS ) && defined( __STDC__ )
+#define NEEDPROTOS
+#endif
+
+#ifdef _SLDAPD_H_	/* server build: no need to use LDAP_CALL stuff */
+#ifdef LDAP_CALL
+#undef LDAP_CALL
+#define LDAP_CALL
+#endif
+#endif
+
+#ifdef NEEDPROTOS
+int re_init( void );
+void re_lock( void );
+int re_unlock( void );
+char * LDAP_CALL re_comp( const char *pat );
+int LDAP_CALL re_exec( const char *lp );
+void LDAP_CALL re_modw( char *s );
+int LDAP_CALL re_subs( char *src, char *dst );
+#else /* NEEDPROTOS */
+int re_init();
+void re_lock();
+int re_unlock();
+char * LDAP_CALL re_comp();
+int LDAP_CALL re_exec();
+void LDAP_CALL re_modw();
+int LDAP_CALL re_subs();
+#endif /* NEEDPROTOS */
+
+#define re_fail( m, p )
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* macintosh or DOS or or _WIN32 or NEED_BSDREGEX */
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/include/srchpref.h
@@ -0,0 +1,154 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Copyright (c) 1993, 1994 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ *
+ * searchpref.h:  display template library defines
+ */
+
+
+#ifndef _SRCHPREF_H
+#define _SRCHPREF_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* calling conventions used by library */
+#ifndef LDAP_CALL
+#if defined( _WINDOWS ) || defined( _WIN32 )
+#define LDAP_C __cdecl
+#ifndef _WIN32 
+#define __stdcall _far _pascal
+#define LDAP_CALLBACK _loadds
+#else
+#define LDAP_CALLBACK
+#endif /* _WIN32 */
+#define LDAP_PASCAL __stdcall
+#define LDAP_CALL LDAP_PASCAL
+#else /* _WINDOWS */
+#define LDAP_C
+#define LDAP_CALLBACK
+#define LDAP_PASCAL
+#define LDAP_CALL
+#endif /* _WINDOWS */
+#endif /* LDAP_CALL */
+
+struct ldap_searchattr {
+	char				*sa_attrlabel;
+	char				*sa_attr;
+					/* max 32 matchtypes for now */
+	unsigned long			sa_matchtypebitmap;
+	char				*sa_selectattr;
+	char				*sa_selecttext;
+	struct ldap_searchattr		*sa_next;
+};
+
+struct ldap_searchmatch {
+	char				*sm_matchprompt;
+	char				*sm_filter;
+	struct ldap_searchmatch		*sm_next;
+};
+
+struct ldap_searchobj {
+	char				*so_objtypeprompt;
+	unsigned long			so_options;
+	char				*so_prompt;
+	short				so_defaultscope;
+	char				*so_filterprefix;
+	char				*so_filtertag;
+	char				*so_defaultselectattr;
+	char				*so_defaultselecttext;
+	struct ldap_searchattr		*so_salist;
+	struct ldap_searchmatch		*so_smlist;
+	struct ldap_searchobj		*so_next;
+};
+
+#define NULLSEARCHOBJ			((struct ldap_searchobj *)0)
+
+/*
+ * global search object options
+ */
+#define LDAP_SEARCHOBJ_OPT_INTERNAL	0x00000001
+
+#define LDAP_IS_SEARCHOBJ_OPTION_SET( so, option )	\
+	(((so)->so_options & option ) != 0 )
+
+#define LDAP_SEARCHPREF_VERSION_ZERO	0
+#define LDAP_SEARCHPREF_VERSION		1
+
+#define LDAP_SEARCHPREF_ERR_VERSION	1
+#define LDAP_SEARCHPREF_ERR_MEM		2
+#define LDAP_SEARCHPREF_ERR_SYNTAX	3
+#define LDAP_SEARCHPREF_ERR_FILE	4
+
+
+LDAP_API(int)
+LDAP_CALL
+ldap_init_searchprefs( char *file, struct ldap_searchobj **solistp );
+
+LDAP_API(int)
+LDAP_CALL
+ldap_init_searchprefs_buf( char *buf, long buflen,
+	struct ldap_searchobj **solistp );
+
+LDAP_API(void)
+LDAP_CALL
+ldap_free_searchprefs( struct ldap_searchobj *solist );
+
+LDAP_API(struct ldap_searchobj *)
+LDAP_CALL
+ldap_first_searchobj( struct ldap_searchobj *solist );
+
+LDAP_API(struct ldap_searchobj *)
+LDAP_CALL
+ldap_next_searchobj( struct ldap_searchobj *sollist,
+	struct ldap_searchobj *so );
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _SRCHPREF_H */
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libiutil/Makefile.in
@@ -0,0 +1,110 @@
+# 
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+# 
+# The contents of this file are subject to the Mozilla Public License Version 
+# 1.1 (the "License"); you may not use this file except in compliance with 
+# the License. You may obtain a copy of the License at 
+# http://www.mozilla.org/MPL/
+# 
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+# 
+# The Original Code is Mozilla Communicator client code, released
+# March 31, 1998.
+# 
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 1998-1999
+# the Initial Developer. All Rights Reserved.
+# 
+# Contributor(s):
+# 
+# Alternatively, the contents of this file may be used under the terms of
+# either of the GNU General Public License Version 2 or later (the "GPL"),
+# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+# 
+# ***** END LICENSE BLOCK ***** 
+
+
+MOD_DEPTH	= ../../..
+srcdir		= @srcdir@
+topsrcdir 	= @top_srcdir@
+
+include $(MOD_DEPTH)/config/autoconf.mk
+include $(topsrcdir)/build.mk
+
+ifeq ($(HAVE_CCONF), 1)
+SRCS		= iutil-lock.c
+else
+SRCS		= iutil-lock.c
+endif
+
+REALOBJS        = $(SRCS:.c=.$(OBJ_SUFFIX))
+
+IUTILOBJDEST	= $(OBJDIR_NAME)
+OBJS		= $(addprefix $(IUTILOBJDEST)/, $(REALOBJS))
+
+DISTHDIR	= $(DIST)/public/ldap
+HDIR		= $(topsrcdir)/ldap/include
+
+LIBIUTIL	= $(addprefix $(IUTILOBJDEST)/, \
+		  $(LIB_PREFIX)$(IUTIL_LIBNAME).$(LIB_SUFFIX))
+
+INSTALLDIR      = $(DIST)/$(OBJDIR_NAME)
+
+include $(topsrcdir)/config/rules.mk
+
+GARBAGE 	+= $(LIBIUTIL)
+
+LOCAL_INCLUDES  = -I$(PUBLIC)/nspr
+INCLUDES	+= -I$(DISTHDIR) -I$(HDIR) -I$(INSTALLDIR)/include -I$(DIST)/include
+ifeq ($(HAVE_CCONF), 1)
+INCLUDES	+= -I$(srcdir)/../libldap/
+endif
+DEFINES		+= $(DEFS)
+
+PLATFORMCFLAGS	= -DUSE_WAITPID -DNEEDPROTOS
+PLATFORMLIBS	=
+THREADS		=
+THREADSLIB	=
+
+###########################################################################
+
+versiont.c:	Makefile.client Version.c
+	@$(RM) $@
+	@(u="$${USER-root}" v="$(shell cat ../../build/version)" d="$(shell pwd)" \
+	h="$(shell hostname)" t="$(shell date)"; $(SED) -e "s|%WHEN%|$${t}|" \
+	-e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
+	-e "s|%VERSION%|$${v}|" \
+	< Version.c > $@)
+
+export::    $(OBJDEST) $(LIBDIR) $(OBJS) $(LIBIUTIL)
+
+$(LIBDIR):
+	$(MKDIR) $(LIBDIR)
+
+$(LIBIUTIL): $(OBJS) $(LIBDIR)
+	@echo ======= making $(LIBIUTIL)
+ifdef SO_FILES_TO_REMOVE
+	-$(RM) $(SO_FILES_TO_REMOVE)
+endif
+	$(LINK_LIB)
+
+veryclean:: clean
+
+$(OBJDEST):
+	$(MKDIR) $(OBJDEST)
+
+export::	$(LIBIUTIL)
+	$(INSTALL) -m 444 $(LIBIUTIL) $(dist_libdir)
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libiutil/iutil-lock.c
@@ -0,0 +1,103 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Public interface for libiutil the innosoft migration library
+ *
+ */
+
+#ifdef _WINDOWS
+
+#include "ldap.h"
+
+#define LDAP_MUTEX_T    HANDLE
+
+int
+pthread_mutex_init( LDAP_MUTEX_T *mp, void *attr)
+{
+        if ( (*mp = CreateMutex(NULL, FALSE, NULL)) == NULL )
+                return( 1 );
+        else
+                return( 0 );
+}
+
+static void *
+pthread_mutex_alloc( void )
+{
+        LDAP_MUTEX_T *mutexp;
+
+        if ( (mutexp = malloc( sizeof(LDAP_MUTEX_T) )) != NULL ) {
+                pthread_mutex_init( mutexp, NULL );
+        }
+        return( mutexp );
+}
+
+int
+pthread_mutex_destroy( LDAP_MUTEX_T *mp )
+{
+        if ( !(CloseHandle(*mp)) )
+                return( 1 );
+        else
+                return( 0 );
+}
+
+static void
+pthread_mutex_free( void *mutexp )
+{
+        pthread_mutex_destroy( (LDAP_MUTEX_T *) mutexp );
+        free( mutexp );
+}
+
+int
+pthread_mutex_lock( LDAP_MUTEX_T *mp )
+{
+        if ( (WaitForSingleObject(*mp, INFINITE) != WAIT_OBJECT_0) )
+                return( 1 );
+        else
+                return( 0 );
+}
+
+
+int
+pthread_mutex_unlock( LDAP_MUTEX_T *mp )
+{
+        if ( !(ReleaseMutex(*mp)) )
+                return( 1 );
+        else
+                return( 0 );
+}
+#endif /* WINDOWS */
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/liblber/Makefile.in
@@ -0,0 +1,104 @@
+# 
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+# 
+# The contents of this file are subject to the Mozilla Public License Version 
+# 1.1 (the "License"); you may not use this file except in compliance with 
+# the License. You may obtain a copy of the License at 
+# http://www.mozilla.org/MPL/
+# 
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+# 
+# The Original Code is Mozilla Communicator client code, released
+# March 31, 1998.
+# 
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 1998-1999
+# the Initial Developer. All Rights Reserved.
+# 
+# Contributor(s):
+# 
+# Alternatively, the contents of this file may be used under the terms of
+# either of the GNU General Public License Version 2 or later (the "GPL"),
+# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+# 
+# ***** END LICENSE BLOCK ***** 
+
+MOD_DEPTH	= ../../..
+srcdir		= @srcdir@
+topsrcdir 	= @top_srcdir@
+HAVE_SASL	= @HAVE_SASL@
+SASL_CFLAGS	= @SASL_CFLAGS@
+
+include $(MOD_DEPTH)/config/autoconf.mk
+include $(topsrcdir)/build.mk
+
+SRCS		= decode.c \
+		  encode.c \
+		  io.c \
+		  bprint.c
+
+REALOBJS        = $(SRCS:.c=.$(OBJ_SUFFIX))
+OBJS		= $(addprefix $(OBJDIR_NAME)/, $(REALOBJS))
+HDIR		= $(topsrcdir)/ldap/include
+
+LIBLBER		= $(addprefix $(OBJDIR_NAME)/, $(LIB_PREFIX)$(LBER_LIBNAME).$(LIB_SUFFIX))
+
+INSTALLDIR	= $(DIST)/$(OBJDIR_NAME)
+
+include $(topsrcdir)/config/rules.mk
+
+GARBAGE 	+= $(LIBLBER)
+
+LOCAL_INCLUDES  =
+INCLUDES	+= -I$(HDIR)  -I$(INSTALLDIR)/include 
+
+DEFINES		+= $(DEFS)
+
+PLATFORMCFLAGS	= -DUSE_WAITPID -DNEEDPROTOS
+PLATFORMLIBS	=
+THREADS		=
+THREADSLIB	=
+
+###########################################################################
+
+versiont.c:	Makefile.client Version.c
+	@$(RM) $@
+	@(u="$${USER-root}" v="$(shell cat ../../build/version)" d="$(shell pwd)" \
+	h="$(shell hostname)" t="$(shell date)"; $(SED) -e "s|%WHEN%|$${t}|" \
+	-e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
+	-e "s|%VERSION%|$${v}|" \
+	< Version.c > $@)
+
+export::    $(OBJDEST) $(LIBDIR) $(OBJS) $(LIBLBER)
+
+$(LIBDIR):
+	$(MKDIR) $(LIBDIR)
+
+$(LIBLBER): $(OBJS) $(LIBDIR)
+	@echo ======= making $(LIBLBER)
+ifdef SO_FILES_TO_REMOVE
+	-$(RM) $(SO_FILES_TO_REMOVE)
+endif
+	$(LINK_LIB)
+
+veryclean:: clean
+
+$(OBJDEST):
+	$(MKDIR) $(OBJDEST)
+
+export::  $(LIBLBER)
+	$(INSTALL) -m 444 $(LIBLBER) $(dist_libdir)
+
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/liblber/bprint.c
@@ -0,0 +1,102 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+/* bprint.c - a printing utility for debuging output */
+#include <string.h>
+#include "lber-int.h"
+
+#ifdef LDAP_DEBUG
+/*
+ * Print arbitrary stuff, for debugging.
+ */
+
+#define BPLEN	48
+
+void
+lber_bprint( char *data, int len )
+{
+    static char	hexdig[] = "0123456789abcdef";
+    char	out[ BPLEN ];
+    int		i = 0;
+
+    memset( out, 0, BPLEN );
+    for ( ;; ) {
+	if ( len < 1 ) {
+		char msg[BPLEN + 80];
+	    sprintf( msg, "\t%s\n", ( i == 0 ) ? "(end)" : out );
+		ber_err_print( msg );
+	    break;
+	}
+
+#ifndef HEX
+	if ( isgraph( (unsigned char)*data )) {
+	    out[ i ] = ' ';
+	    out[ i+1 ] = *data;
+	} else {
+#endif
+	    out[ i ] = hexdig[ ( *data & 0xf0 ) >> 4 ];
+	    out[ i+1 ] = hexdig[ *data & 0x0f ];
+#ifndef HEX
+	}
+#endif
+	i += 2;
+	len--;
+	data++;
+
+	if ( i > BPLEN - 2 ) {
+		char msg[BPLEN + 80];
+	    sprintf( msg, "\t%s\n", out );
+		ber_err_print( msg );
+	    memset( out, 0, BPLEN );
+	    i = 0;
+	    continue;
+	}
+	out[ i++ ] = ' ';
+    }
+}
+
+#endif
+
+void ber_err_print( char *data )
+{
+#ifdef USE_DEBUG_WIN
+	OutputDebugString( data );
+#else
+	fputs( data, stderr );
+	fflush( stderr );
+#endif
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/liblber/decode.c
@@ -0,0 +1,833 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+/* decode.c - ber input decoding routines */
+
+#include "lber-int.h"
+
+/*
+ * Note: ber_get_tag() only uses the ber_end and ber_ptr elements of ber.
+ * If that changes, the ber_peek_tag() and/or ber_skip_tag() implementations
+ * will need to be changed.
+ */
+/* return the tag - LBER_DEFAULT returned means trouble */
+ber_tag_t
+LDAP_CALL
+ber_get_tag( BerElement *ber )
+{
+	unsigned char	xbyte;
+	ber_tag_t		tag;
+	char			*tagp;
+	int				i;
+
+	if ( ber_read( ber, (char *) &xbyte, 1 ) != 1 )
+		return( LBER_DEFAULT );
+
+	if ( (xbyte & LBER_BIG_TAG_MASK) != LBER_BIG_TAG_MASK )
+		return( (ber_uint_t) xbyte );
+
+	tagp = (char *) &tag;
+	tagp[0] = xbyte;
+	for ( i = 1; i < sizeof(ber_int_t); i++ ) {
+		if ( ber_read( ber, (char *) &xbyte, 1 ) != 1 )
+			return( LBER_DEFAULT );
+
+		tagp[i] = xbyte;
+
+		if ( ! (xbyte & LBER_MORE_TAG_MASK) )
+			break;
+	}
+
+	/* tag too big! */
+	if ( i == sizeof(ber_int_t) )
+		return( LBER_DEFAULT );
+
+	/* want leading, not trailing 0's */
+	return( tag >> (sizeof(ber_int_t) - i - 1) );
+}
+
+/*
+ * Note: ber_skip_tag() only uses the ber_end and ber_ptr elements of ber.
+ * If that changes, the implementation of ber_peek_tag() will need to
+ * be changed.
+ */
+ber_tag_t
+LDAP_CALL
+ber_skip_tag( BerElement *ber, ber_len_t *len )
+{
+	ber_tag_t		tag;
+	unsigned char	lc;
+	int				noctets, diff;
+	ber_len_t		netlen;
+
+	/*
+	 * Any ber element looks like this: tag length contents.
+	 * Assuming everything's ok, we return the tag byte (we
+	 * can assume a single byte), and return the length in len.
+	 *
+	 * Assumptions:
+	 *	1) definite lengths
+	 *	2) primitive encodings used whenever possible
+	 */
+
+	/*
+	 * First, we read the tag.
+	 */
+
+	if ( (tag = ber_get_tag( ber )) == LBER_DEFAULT )
+		return( LBER_DEFAULT );
+
+	/*
+	 * Next, read the length.  The first byte contains the length of
+	 * the length.  If bit 8 is set, the length is the long form,
+	 * otherwise it's the short form.  We don't allow a length that's
+	 * greater than what we can hold in an unsigned long.
+	 */
+
+	*len = netlen = 0;
+	if ( ber_read( ber, (char *) &lc, 1 ) != 1 )
+		return( LBER_DEFAULT );
+	if ( lc & 0x80 ) {
+		noctets = (lc & 0x7f);
+		if ( noctets > sizeof(ber_uint_t) )
+			return( LBER_DEFAULT );
+		diff = sizeof(ber_int_t) - noctets;
+		if ( ber_read( ber, (char *) &netlen + diff, noctets )
+		    != noctets )
+			return( LBER_DEFAULT );
+		*len = LBER_NTOHL( netlen );
+	} else {
+		*len = lc;
+	}
+
+	return( tag );
+}
+
+
+/*
+ * Note: Previously, we passed the "ber" parameter directly to ber_skip_tag(),
+ * saving and restoring the ber_ptr element only.  We now take advantage
+ * of the fact that the only ber structure elements touched by ber_skip_tag()
+ * are ber_end and ber_ptr.  If that changes, this code must change too.
+ */
+ber_tag_t
+LDAP_CALL
+ber_peek_tag( BerElement *ber, ber_len_t *len )
+{
+	BerElement	bercopy;
+
+	bercopy.ber_end = ber->ber_end;
+	bercopy.ber_ptr = ber->ber_ptr;
+	return( ber_skip_tag( &bercopy, len ));
+}
+
+static int
+ber_getnint( BerElement *ber, ber_int_t *num, ber_slen_t len )
+{
+	int				i;
+	ber_int_t		value;
+	unsigned char	buffer[sizeof(ber_int_t)];
+	/*
+	 * The tag and length have already been stripped off.  We should
+	 * be sitting right before len bytes of 2's complement integer,
+	 * ready to be read straight into an int.  We may have to sign
+	 * extend after we read it in.
+	 */
+
+	if ( len > sizeof(ber_slen_t) )
+		return( -1 );
+
+	/* read into the low-order bytes of netnum */
+	if ( ber_read( ber, (char *) buffer, len ) != len )
+		return( -1 );
+
+	/* This sets the required sign extension */
+	if ( len != 0) {
+		value = 0x80 & buffer[0] ? (-1) : 0;
+	} else {
+		value = 0;
+	}
+		
+	for ( i = 0; i < len; i++ )
+	  value = (value << 8) | buffer[i];
+	
+	*num = value;
+	
+	return( len );
+}
+
+ber_tag_t
+LDAP_CALL
+ber_get_int( BerElement *ber, ber_int_t *num )
+{
+	ber_tag_t	tag;
+	ber_len_t	len;
+
+	if ( (tag = ber_skip_tag( ber, &len )) == LBER_DEFAULT )
+		return( LBER_DEFAULT );
+
+	/*
+     * len is being demoted to a long here --  possible conversion error
+     */
+  
+	if ( ber_getnint( ber, num, (int)len ) != (ber_slen_t)len )
+		return( LBER_DEFAULT );
+	else
+		return( tag );
+}
+
+ber_tag_t
+LDAP_CALL
+ber_get_stringb( BerElement *ber, char *buf, ber_len_t *len )
+{
+	ber_len_t	datalen;
+	ber_tag_t	tag;
+#ifdef STR_TRANSLATION
+	char		*transbuf;
+#endif /* STR_TRANSLATION */
+
+	if ( (tag = ber_skip_tag( ber, &datalen )) == LBER_DEFAULT )
+		return( LBER_DEFAULT );
+	if ( datalen > (*len - 1) )
+		return( LBER_DEFAULT );
+
+	/*
+     * datalen is being demoted to a long here --  possible conversion error
+     */
+
+	if ( ber_read( ber, buf, datalen ) != (ber_slen_t) datalen )
+		return( LBER_DEFAULT );
+
+	buf[datalen] = '\0';
+
+#ifdef STR_TRANSLATION
+	if ( datalen > 0 && ( ber->ber_options & LBER_OPT_TRANSLATE_STRINGS )
+	    != 0 && ber->ber_decode_translate_proc != NULL ) {
+		transbuf = buf;
+		++datalen;
+		if ( (*(ber->ber_decode_translate_proc))( &transbuf, &datalen,
+		    0 ) != 0 ) {
+			return( LBER_DEFAULT );
+		}
+		if ( datalen > *len ) {
+			NSLBERI_FREE( transbuf );
+			return( LBER_DEFAULT );
+		}
+		SAFEMEMCPY( buf, transbuf, datalen );
+		NSLBERI_FREE( transbuf );
+		--datalen;
+	}
+#endif /* STR_TRANSLATION */
+
+	*len = datalen;
+	return( tag );
+}
+
+ber_tag_t
+LDAP_CALL
+ber_get_stringa( BerElement *ber, char **buf )
+{
+	ber_len_t	datalen, ndatalen;
+	ber_tag_t	tag;
+
+	if ( (tag = ber_skip_tag( ber, &datalen )) == LBER_DEFAULT )
+		return( LBER_DEFAULT );
+
+	if ( ((ndatalen = (size_t)datalen + 1) < (size_t) datalen) ||
+	   ( datalen > (ber->ber_end - ber->ber_ptr) ) ||
+	   ( (*buf = (char *)NSLBERI_MALLOC( (size_t)ndatalen )) == NULL ))
+		return( LBER_DEFAULT );
+
+    /*
+     * datalen is being demoted to a long here --  possible conversion error
+     */
+	if ( ber_read( ber, *buf, datalen ) != (ber_slen_t) datalen ) {
+		NSLBERI_FREE( *buf );
+		*buf = NULL;
+		return( LBER_DEFAULT );
+	}
+
+	(*buf)[datalen] = '\0';
+
+#ifdef STR_TRANSLATION
+	if ( datalen > 0 && ( ber->ber_options & LBER_OPT_TRANSLATE_STRINGS )
+	    != 0 && ber->ber_decode_translate_proc != NULL ) {
+		++datalen;
+		if ( (*(ber->ber_decode_translate_proc))( buf, &datalen, 1 )
+		    != 0 ) {
+			NSLBERI_FREE( *buf );
+			*buf = NULL;
+			return( LBER_DEFAULT );
+		}
+	}
+#endif /* STR_TRANSLATION */
+
+	return( tag );
+}
+
+ber_tag_t
+LDAP_CALL
+ber_get_stringal( BerElement *ber, struct berval **bv )
+{
+	ber_len_t	len, nlen;
+	ber_tag_t	tag;
+
+	if ( (*bv = (struct berval *)NSLBERI_MALLOC( sizeof(struct berval) ))
+	    == NULL ) {
+		return( LBER_DEFAULT );
+	}
+	
+	(*bv)->bv_val = NULL;
+	(*bv)->bv_len = 0;
+
+	if ( (tag = ber_skip_tag( ber, &len )) == LBER_DEFAULT ) {
+		NSLBERI_FREE( *bv );
+		*bv = NULL;
+		return( LBER_DEFAULT );
+	}
+
+	if ( ((nlen = (size_t) len + 1) < (size_t)len) ||
+	     ( len > (ber->ber_end - ber->ber_ptr) ) ||
+	     (((*bv)->bv_val = (char *)NSLBERI_MALLOC( (size_t)nlen ))
+	    == NULL )) {
+		NSLBERI_FREE( *bv );
+		*bv = NULL;
+		return( LBER_DEFAULT );
+	}
+
+    /*
+     * len is being demoted to a long here --  possible conversion error
+     */
+	if ( ber_read( ber, (*bv)->bv_val, len ) != (ber_slen_t) len ) {
+		NSLBERI_FREE( (*bv)->bv_val );
+		(*bv)->bv_val = NULL;
+		NSLBERI_FREE( *bv );
+		*bv = NULL;
+		return( LBER_DEFAULT );
+	}
+
+	((*bv)->bv_val)[len] = '\0';
+	(*bv)->bv_len = len;
+
+#ifdef STR_TRANSLATION
+	if ( len > 0 && ( ber->ber_options & LBER_OPT_TRANSLATE_STRINGS ) != 0
+	    && ber->ber_decode_translate_proc != NULL ) {
+		++len;
+		if ( (*(ber->ber_decode_translate_proc))( &((*bv)->bv_val),
+		    &len, 1 ) != 0 ) {
+			NSLBERI_FREE( (*bv)->bv_val );
+			(*bv)->bv_val = NULL;
+			NSLBERI_FREE( *bv );
+			*bv = NULL;
+			return( LBER_DEFAULT );
+		}
+		(*bv)->bv_len = len - 1;
+	}
+#endif /* STR_TRANSLATION */
+
+	return( tag );
+}
+
+ber_tag_t
+LDAP_CALL
+ber_get_bitstringa( BerElement *ber, char **buf, ber_len_t *blen )
+{
+	ber_len_t		datalen;
+	ber_tag_t		tag;
+	unsigned char	unusedbits;
+
+	if ( (tag = ber_skip_tag( ber, &datalen )) == LBER_DEFAULT )
+		return( LBER_DEFAULT );
+	--datalen;
+
+	if ( (datalen > (ber->ber_end - ber->ber_ptr)) ||
+	   ( (*buf = (char *)NSLBERI_MALLOC((size_t)datalen )) == NULL ) )
+		return( LBER_DEFAULT );
+
+	if ( ber_read( ber, (char *)&unusedbits, 1 ) != 1 ) {
+		NSLBERI_FREE( *buf );
+		*buf = NULL;
+		return( LBER_DEFAULT );
+	}
+
+	/*
+     * datalen is being demoted to a long here --  possible conversion error
+     */
+	if ( ber_read( ber, *buf, datalen ) != (ber_slen_t) datalen ) {
+		NSLBERI_FREE( *buf );
+		*buf = NULL;
+		return( LBER_DEFAULT );
+	}
+
+	*blen = datalen * 8 - unusedbits;
+	return( tag );
+}
+
+ber_tag_t
+LDAP_CALL
+ber_get_null( BerElement *ber )
+{
+	ber_len_t	len;
+	ber_tag_t	tag;
+
+	if ( (tag = ber_skip_tag( ber, &len )) == LBER_DEFAULT )
+		return( LBER_DEFAULT );
+
+	if ( len != 0 )
+		return( LBER_DEFAULT );
+
+	return( tag );
+}
+
+ber_tag_t
+LDAP_CALL
+ber_get_boolean( BerElement *ber, ber_int_t *boolval )
+{
+	int	rc;
+
+	rc = ber_get_int( ber, boolval );
+
+	return( rc );
+}
+
+ber_tag_t
+LDAP_CALL
+ber_first_element( BerElement *ber, ber_len_t *len, char **last )
+{
+	/* skip the sequence header, use the len to mark where to stop */
+	if ( ber_skip_tag( ber, len ) == LBER_DEFAULT ) {
+		return( LBER_ERROR );
+	}
+
+	*last = ber->ber_ptr + *len;
+
+	if ( *last == ber->ber_ptr ) {
+		return( LBER_END_OF_SEQORSET );
+	}
+
+	return( ber_peek_tag( ber, len ) );
+}
+
+ber_tag_t
+LDAP_CALL
+ber_next_element( BerElement *ber, ber_len_t *len, char *last )
+{
+	if ( ber->ber_ptr == last ) {
+		return( LBER_END_OF_SEQORSET );
+	}
+
+	return( ber_peek_tag( ber, len ) );
+}
+
+/* VARARGS */
+ber_tag_t
+LDAP_C
+ber_scanf( BerElement *ber, const char *fmt, ... )
+{
+	va_list			ap;
+	char			*last, *p;
+	char			*s, **ss, ***sss;
+	struct berval 	***bv, **bvp, *bval;
+	int				*i, j;
+	ber_int_t		*l, rc, tag;
+	ber_tag_t		*t;
+	ber_len_t		len;
+	size_t			array_size;
+	
+	va_start( ap, fmt );
+
+#ifdef LDAP_DEBUG
+	if ( lber_debug & 64 ) {
+		char msg[80];
+		sprintf( msg, "ber_scanf fmt (%s) ber:\n", fmt );
+		ber_err_print( msg );
+		ber_dump( ber, 1 );
+	}
+#endif
+	for ( rc = 0, p = (char *) fmt; *p && rc != LBER_DEFAULT; p++ ) {
+		switch ( *p ) {
+		case 'a':	/* octet string - allocate storage as needed */
+			ss = va_arg( ap, char ** );
+			rc = ber_get_stringa( ber, ss );
+			break;
+
+		case 'b':	/* boolean */
+			i = va_arg( ap, int * );
+			rc = ber_get_boolean( ber, i );
+			break;
+
+		case 'e':	/* enumerated */
+		case 'i':	/* int */
+			l = va_arg( ap, ber_slen_t * );
+			rc = ber_get_int( ber, l );
+			break;
+
+		case 'l':	/* length of next item */
+			l = va_arg( ap, ber_slen_t * );
+			rc = ber_peek_tag( ber, (ber_len_t *)l );
+			break;
+
+		case 'n':	/* null */
+			rc = ber_get_null( ber );
+			break;
+
+		case 's':	/* octet string - in a buffer */
+			s = va_arg( ap, char * );
+			l = va_arg( ap, ber_slen_t * );
+			rc = ber_get_stringb( ber, s, (ber_len_t *)l );
+			break;
+
+		case 'o':	/* octet string in a supplied berval */
+			bval = va_arg( ap, struct berval * );
+			ber_peek_tag( ber, &bval->bv_len );
+			rc = ber_get_stringa( ber, &bval->bv_val );
+			break;
+
+		case 'O':	/* octet string - allocate & include length */
+			bvp = va_arg( ap, struct berval ** );
+			rc = ber_get_stringal( ber, bvp );
+			break;
+
+		case 'B':	/* bit string - allocate storage as needed */
+			ss = va_arg( ap, char ** );
+			l = va_arg( ap, ber_slen_t * ); /* for length, in bits */
+			rc = ber_get_bitstringa( ber, ss, (ber_len_t *)l );
+			break;
+
+		case 't':	/* tag of next item */
+			t = va_arg( ap, ber_tag_t * );
+			*t = rc = ber_peek_tag( ber, &len );
+			break;
+
+		case 'T':	/* skip tag of next item */
+			t = va_arg( ap, ber_tag_t * );
+			*t = rc = ber_skip_tag( ber, &len );
+			break;
+
+		case 'v':	/* sequence of strings */
+			sss = va_arg( ap, char *** );
+			*sss = NULL;
+			j = 0;
+			array_size = 0;
+			for ( tag = ber_first_element( ber, &len, &last );
+			    tag != LBER_DEFAULT && tag != LBER_END_OF_SEQORSET
+			    && rc != LBER_DEFAULT;
+			    tag = ber_next_element( ber, &len, last ) ) {
+				if ( *sss == NULL ) {
+				    /* Make room for at least 15 strings */
+				    *sss = (char **)NSLBERI_MALLOC(16 * sizeof(char *) );
+					if (!*sss) {
+						rc = LBER_DEFAULT;
+						break; /* out of memory - cannot continue */
+                    }
+				    array_size = 16;
+				} else {
+				    char **save_sss = *sss;
+				    if ( (size_t)(j+2) > array_size) {
+						/* We'v overflowed our buffer */
+						*sss = (char **)NSLBERI_REALLOC( *sss, (array_size * 2) * sizeof(char *) );
+						array_size = array_size * 2;
+				    }
+					if (!*sss) {
+						rc = LBER_DEFAULT;
+						ber_svecfree(save_sss);
+						break; /* out of memory - cannot continue */
+					}
+				}
+				(*sss)[j] = NULL;
+				rc = ber_get_stringa( ber, &((*sss)[j]) );
+				j++;
+			}
+			if ( rc != LBER_DEFAULT &&
+			    tag != LBER_END_OF_SEQORSET ) {
+				rc = LBER_DEFAULT;
+			}
+			if ( *sss && (j > 0) ) {
+				(*sss)[j] = NULL;
+			}
+			break;
+
+		case 'V':	/* sequence of strings + lengths */
+			bv = va_arg( ap, struct berval *** );
+			*bv = NULL;
+			j = 0;
+			for ( tag = ber_first_element( ber, &len, &last );
+			    tag != LBER_DEFAULT && tag != LBER_END_OF_SEQORSET
+			    && rc != LBER_DEFAULT;
+			    tag = ber_next_element( ber, &len, last ) ) {
+				if ( *bv == NULL ) {
+					*bv = (struct berval **)NSLBERI_MALLOC(
+					    2 * sizeof(struct berval *) );
+					if (!*bv) {
+						rc = LBER_DEFAULT;
+						break; /* out of memory - cannot continue */
+					}
+				} else {
+					struct berval **save_bv = *bv;
+					*bv = (struct berval **)NSLBERI_REALLOC(
+					    *bv,
+					    (j + 2) * sizeof(struct berval *) );
+					if (!*bv) {
+						rc = LBER_DEFAULT;
+						ber_bvecfree(save_bv);
+						break; /* out of memory - cannot continue */
+					}
+				}
+				rc = ber_get_stringal( ber, &((*bv)[j]) );
+				j++;
+			}
+			if ( rc != LBER_DEFAULT &&
+			    tag != LBER_END_OF_SEQORSET ) {
+				rc = LBER_DEFAULT;
+			}
+			if ( *bv && (j > 0) ) {
+				(*bv)[j] = NULL;
+			}
+			break;
+
+		case 'x':	/* skip the next element - whatever it is */
+			if ( (rc = ber_skip_tag( ber, &len )) == LBER_DEFAULT )
+				break;
+			ber->ber_ptr += len;
+			break;
+
+		case '{':	/* begin sequence */
+		case '[':	/* begin set */
+			if ( *(p + 1) != 'v' && *(p + 1) != 'V' )
+				rc = ber_skip_tag( ber, &len );
+			break;
+
+		case '}':	/* end sequence */
+		case ']':	/* end set */
+			break;
+
+		default:
+			{
+				char msg[80];
+				sprintf( msg, "unknown fmt %c\n", *p );
+				ber_err_print( msg );
+			}
+			rc = LBER_DEFAULT;
+			break;
+		}
+	}
+
+	va_end( ap );
+
+	if (rc == LBER_DEFAULT) {
+	  va_start( ap, fmt );
+	  for ( p--; fmt < p && *fmt; fmt++ ) {
+		switch ( *fmt ) {
+		case 'a':	/* octet string - allocate storage as needed */
+			ss = va_arg( ap, char ** );
+			NSLBERI_FREE(*ss);
+			*ss = NULL;
+			break;
+
+		case 'b':	/* boolean */
+			i = va_arg( ap, int * );
+			break;
+
+		case 'e':	/* enumerated */
+		case 'i':	/* int */
+			l = va_arg( ap, ber_slen_t * );
+			break;
+
+		case 'l':	/* length of next item */
+			l = va_arg( ap, ber_slen_t * );
+			break;
+
+		case 'n':	/* null */
+			break;
+
+		case 's':	/* octet string - in a buffer */
+			s = va_arg( ap, char * );
+			l = va_arg( ap, ber_slen_t * );
+			break;
+
+		case 'o':	/* octet string in a supplied berval */
+			bval = va_arg( ap, struct berval * );
+			if (bval->bv_val) NSLBERI_FREE(bval->bv_val);
+			memset(bval, 0, sizeof(struct berval));
+			break;
+
+		case 'O':	/* octet string - allocate & include length */
+			bvp = va_arg( ap, struct berval ** );
+			ber_bvfree(*bvp);
+			bvp = NULL;
+			break;
+
+		case 'B':	/* bit string - allocate storage as needed */
+			ss = va_arg( ap, char ** );
+			l = va_arg( ap, ber_slen_t * ); /* for length, in bits */
+			if (*ss) NSLBERI_FREE(*ss);
+			*ss = NULL;
+			break;
+
+		case 't':	/* tag of next item */
+			t = va_arg( ap, ber_tag_t * );
+			break;
+
+		case 'T':	/* skip tag of next item */
+			t = va_arg( ap, ber_tag_t * );
+			break;
+
+		case 'v':	/* sequence of strings */
+			sss = va_arg( ap, char *** );
+			ber_svecfree(*sss);
+			*sss = NULL;
+			break;
+
+		case 'V':	/* sequence of strings + lengths */
+			bv = va_arg( ap, struct berval *** );
+			ber_bvecfree(*bv);
+			*bv = NULL;
+			break;
+
+		case 'x':	/* skip the next element - whatever it is */
+			break;
+
+		case '{':	/* begin sequence */
+		case '[':	/* begin set */
+			break;
+
+		case '}':	/* end sequence */
+		case ']':	/* end set */
+			break;
+
+		default:
+			break;
+		}
+	  } /* for */
+	  va_end( ap );
+	} /* if */
+
+	return( rc );
+}
+
+void
+LDAP_CALL
+ber_bvfree( struct berval *bv )
+{
+	if ( bv != NULL ) {
+		if ( bv->bv_val != NULL ) {
+			NSLBERI_FREE( bv->bv_val );
+		}
+		NSLBERI_FREE( (char *) bv );
+	}
+}
+
+void
+LDAP_CALL
+ber_bvecfree( struct berval **bv )
+{
+	int	i;
+
+	if ( bv != NULL ) {
+		for ( i = 0; bv[i] != NULL; i++ ) {
+			ber_bvfree( bv[i] );
+		}
+		NSLBERI_FREE( (char *) bv );
+	}
+}
+
+struct berval *
+LDAP_CALL
+ber_bvdup( const struct berval *bv )
+{
+	struct berval	*new;
+
+	if ( (new = (struct berval *)NSLBERI_MALLOC( sizeof(struct berval) ))
+	    == NULL ) {
+		return( NULL );
+	}
+	if ( bv->bv_val == NULL ) {
+	    new->bv_val = NULL;
+	    new->bv_len = 0;
+	} else {
+	    if ( (new->bv_val = (char *)NSLBERI_MALLOC( bv->bv_len + 1 ))
+		== NULL ) {
+			NSLBERI_FREE( new );
+			new = NULL;
+		    return( NULL );
+	    }
+	    SAFEMEMCPY( new->bv_val, bv->bv_val, (size_t) bv->bv_len );
+	    new->bv_val[bv->bv_len] = '\0';
+	    new->bv_len = bv->bv_len;
+	}
+
+	return( new );
+}
+
+void
+LDAP_CALL
+ber_svecfree( char **vals )
+{
+        int     i;
+
+        if ( vals == NULL )
+                return;
+        for ( i = 0; vals[i] != NULL; i++ )
+                NSLBERI_FREE( vals[i] );
+        NSLBERI_FREE( (char *) vals );
+}
+
+#ifdef STR_TRANSLATION
+void
+LDAP_CALL
+ber_set_string_translators(
+    BerElement		*ber,
+    BERTranslateProc	encode_proc,
+    BERTranslateProc	decode_proc
+)
+{
+    ber->ber_encode_translate_proc = encode_proc;
+    ber->ber_decode_translate_proc = decode_proc;
+}
+#endif /* STR_TRANSLATION */
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/liblber/dtest.c
@@ -0,0 +1,113 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+/* dtest.c - lber decoding test program */
+
+#include <stdio.h>
+#include <string.h>
+#ifdef MACOS
+#include <stdlib.h>
+#include <console.h>
+#else /* MACOS */
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <sys/types.h>
+#include <sys/socket.h>
+#endif /* _WIN32 */
+#endif /* MACOS */
+#include "lber.h"
+
+int
+SSL_Recv( int s, char *b, unsigned l, int dummy )
+{
+	return( read( s, b, l ) );
+}
+
+SSL_Send( int s, char *b, unsigned l, int dummy )
+{
+	return( write( s, b, l ) );
+}
+
+static void usage( char *name )
+{
+	fprintf( stderr, "usage: %s < berfile\n", name );
+}
+
+main( int argc, char **argv )
+{
+	long		i, fd;
+	ber_len_t	len;
+	ber_tag_t	tag;
+	BerElement	*ber;
+	Sockbuf		*sb;
+	extern int	lber_debug;
+
+	lber_debug = 255;
+	if ( argc > 1 ) {
+		usage( argv[0] );
+		exit( 1 );
+	}
+
+	sb = ber_sockbuf_alloc();
+	fd = 0;
+	ber_sockbuf_set_option( sb, LBER_SOCKBUF_OPT_DESC, &fd );
+
+	if ( (ber = der_alloc()) == NULL ) {
+		perror( "ber_alloc" );
+		exit( 1 );
+	}
+
+	if ( (tag = ber_get_next( sb, &len, ber )) == LBER_ERROR ) {
+		perror( "ber_get_next" );
+		exit( 1 );
+	}
+	printf( "message has tag 0x%x and length %ld\n", tag, len );
+
+	return( 0 );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/liblber/encode.c
@@ -0,0 +1,699 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+/* encode.c - ber output encoding routines */
+
+#include "lber-int.h"
+
+static int
+ber_calc_taglen( ber_tag_t tag )
+{
+	int			i;
+	ber_int_t	mask;
+
+	/* find the first non-all-zero byte in the tag */
+	for ( i = sizeof(ber_int_t) - 1; i > 0; i-- ) {
+		mask = (0xff << (i * 8));
+		/* not all zero */
+		if ( tag & mask )
+			break;
+	}
+
+	return( i + 1 );
+}
+
+static int
+ber_put_tag( BerElement	*ber, ber_tag_t tag, int nosos )
+{
+	int			taglen;
+	ber_tag_t	ntag;
+
+	taglen = ber_calc_taglen( tag );
+
+	ntag = LBER_HTONL( tag );
+
+	return( ber_write( ber, ((char *) &ntag) + sizeof(ber_int_t) - taglen,
+	    taglen, nosos ) );
+}
+
+static int
+ber_calc_lenlen( ber_len_t len )
+{
+	/*
+	 * short len if it's less than 128 - one byte giving the len,
+	 * with bit 8 0.
+	 */
+
+	if ( len <= 0x7F )
+		return( 1 );
+
+	/*
+	 * long len otherwise - one byte with bit 8 set, giving the
+	 * length of the length, followed by the length itself.
+	 */
+
+	if ( len <= 0xFF )
+		return( 2 );
+	if ( len <= 0xFFFF )
+		return( 3 );
+	if ( len <= 0xFFFFFF )
+		return( 4 );
+
+	return( 5 );
+}
+
+static int
+ber_put_len( BerElement *ber, ber_len_t len, int nosos )
+{
+	int			i;
+	char		lenlen;
+	ber_int_t	mask;
+	ber_len_t	netlen;
+
+	/*
+	 * short len if it's less than 128 - one byte giving the len,
+	 * with bit 8 0.
+	 */
+
+	if ( len <= 127 ) {
+		netlen = LBER_HTONL( len );
+		return( ber_write( ber, (char *) &netlen + sizeof(ber_int_t) - 1,
+		    1, nosos ) );
+	}
+
+	/*
+	 * long len otherwise - one byte with bit 8 set, giving the
+	 * length of the length, followed by the length itself.
+	 */
+
+	/* find the first non-all-zero byte */
+	for ( i = sizeof(ber_int_t) - 1; i > 0; i-- ) {
+		mask = (0xff << (i * 8));
+		/* not all zero */
+		if ( len & mask )
+			break;
+	}
+	lenlen = ++i;
+	if ( lenlen > 4 )
+		return( -1 );
+	lenlen |= 0x80;
+
+	/* write the length of the length */
+	if ( ber_write( ber, &lenlen, 1, nosos ) != 1 )
+		return( -1 );
+
+	/* write the length itself */
+	netlen = LBER_HTONL( len );
+	if ( ber_write( ber, (char *) &netlen + (sizeof(ber_int_t) - i), i, nosos )
+	    != i )
+		return( -1 );
+
+	return( i + 1 );
+}
+
+static int
+ber_put_int_or_enum( BerElement *ber, ber_int_t num, ber_tag_t tag )
+{
+	int			i, sign, taglen;
+	int			len, lenlen;
+	ber_int_t	netnum, mask;
+
+	sign = (num < 0);
+
+	/*
+	 * high bit is set - look for first non-all-one byte
+	 * high bit is clear - look for first non-all-zero byte
+	 */
+	for ( i = sizeof(ber_int_t) - 1; i > 0; i-- ) {
+		mask = (0xff << (i * 8));
+
+		if ( sign ) {
+			/* not all ones */
+			if ( (num & mask) != mask )
+				break;
+		} else {
+			/* not all zero */
+			if ( num & mask )
+				break;
+		}
+	}
+
+	/*
+	 * we now have the "leading byte".  if the high bit on this
+	 * byte matches the sign bit, we need to "back up" a byte.
+	 */
+	mask = (num & (0x80 << (i * 8)));
+	if ( (mask && !sign) || (sign && !mask) )
+		i++;
+
+	len = i + 1;
+
+	if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
+		return( -1 );
+
+	if ( (lenlen = ber_put_len( ber, len, 0 )) == -1 )
+		return( -1 );
+	i++;
+	netnum = LBER_HTONL( num );
+	if ( ber_write( ber, (char *) &netnum + (sizeof(ber_int_t) - i), i, 0 ) 
+		== i) 
+		/* length of tag + length + contents */
+		return( taglen + lenlen + i );
+
+	return( -1 );
+}
+
+int
+LDAP_CALL
+ber_put_enum( BerElement *ber, ber_int_t num, ber_tag_t tag )
+{
+	if ( tag == LBER_DEFAULT )
+		tag = LBER_ENUMERATED;
+
+	return( ber_put_int_or_enum( ber, num, tag ) );
+}
+
+int
+LDAP_CALL
+ber_put_int( BerElement *ber, ber_int_t num, ber_tag_t tag )
+{
+	if ( tag == LBER_DEFAULT )
+		tag = LBER_INTEGER;
+
+	return( ber_put_int_or_enum( ber, num, tag ) );
+}
+
+int
+LDAP_CALL
+ber_put_ostring( BerElement *ber, char *str, ber_len_t len,
+	ber_tag_t tag )
+{
+	int	taglen, lenlen, rc;
+#ifdef STR_TRANSLATION
+	int	free_str;
+#endif /* STR_TRANSLATION */
+
+	if ( tag == LBER_DEFAULT )
+		tag = LBER_OCTETSTRING;
+
+	if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
+		return( -1 );
+
+#ifdef STR_TRANSLATION
+	if ( len > 0 && ( ber->ber_options & LBER_OPT_TRANSLATE_STRINGS ) != 0
+	    && ber->ber_encode_translate_proc != NULL ) {
+		if ( (*(ber->ber_encode_translate_proc))( &str, &len, 0 )
+		    != 0 ) {
+			return( -1 );
+		}
+		free_str = 1;
+	} else {
+		free_str = 0;
+	}
+#endif /* STR_TRANSLATION */
+
+    /*  
+     *  Note:  below is a spot where we limit ber_write 
+     *         to signed long (instead of unsigned long)
+     */
+
+	if ( (lenlen = ber_put_len( ber, len, 0 )) == -1 ||
+		ber_write( ber, str, len, 0 ) != (ber_int_t) len ) {
+		rc = -1;
+	} else {
+		/* return length of tag + length + contents */
+		rc = taglen + lenlen + len;
+	}
+
+#ifdef STR_TRANSLATION
+	if ( free_str ) {
+		NSLBERI_FREE( str );
+	}
+#endif /* STR_TRANSLATION */
+
+	return( rc );
+}
+
+int
+LDAP_CALL
+ber_put_string( BerElement *ber, char *str, ber_tag_t tag )
+{
+	return( ber_put_ostring( ber, str, (ber_len_t) strlen( str ), tag ));
+}
+
+int
+LDAP_CALL
+ber_put_bitstring( BerElement *ber, char *str,
+	ber_len_t blen /* in bits */, ber_tag_t tag )
+{
+	int		taglen, lenlen, len;
+	unsigned char	unusedbits;
+
+	if ( tag == LBER_DEFAULT )
+		tag = LBER_BITSTRING;
+
+	if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
+		return( -1 );
+
+	len = ( blen + 7 ) / 8;
+	unusedbits = (unsigned char) (len * 8 - blen);
+	if ( (lenlen = ber_put_len( ber, len + 1, 0 )) == -1 )
+		return( -1 );
+
+	if ( ber_write( ber, (char *)&unusedbits, 1, 0 ) != 1 )
+		return( -1 );
+
+	if ( ber_write( ber, str, len, 0 ) != len )
+		return( -1 );
+
+	/* return length of tag + length + unused bit count + contents */
+	return( taglen + 1 + lenlen + len );
+}
+
+int
+LDAP_CALL
+ber_put_null( BerElement *ber, ber_tag_t tag )
+{
+	int	taglen;
+
+	if ( tag == LBER_DEFAULT )
+		tag = LBER_NULL;
+
+	if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
+		return( -1 );
+
+	if ( ber_put_len( ber, 0, 0 ) != 1 )
+		return( -1 );
+
+	return( taglen + 1 );
+}
+
+int
+LDAP_CALL
+ber_put_boolean( BerElement *ber, ber_int_t boolval, ber_tag_t tag )
+{
+	int		taglen;
+	unsigned char	trueval = 0xff;
+	unsigned char	falseval = 0x00;
+
+	if ( tag == LBER_DEFAULT )
+		tag = LBER_BOOLEAN;
+
+	if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
+		return( -1 );
+
+	if ( ber_put_len( ber, 1, 0 ) != 1 )
+		return( -1 );
+
+	if ( ber_write( ber, (char *)(boolval ? &trueval : &falseval), 1, 0 )
+	    != 1 )
+		return( -1 );
+
+	return( taglen + 2 );
+}
+
+#define FOUR_BYTE_LEN	5
+
+
+/* the idea here is roughly this: we maintain a stack of these Seqorset
+ * structures. This is pushed when we see the beginning of a new set or
+ * sequence. It is popped when we see the end of a set or sequence.
+ * Since we don't want to malloc and free these structures all the time,
+ * we pre-allocate a small set of them within the ber element structure.
+ * thus we need to spot when we've overflowed this stack and fall back to
+ * malloc'ing instead.
+ */
+static int
+ber_start_seqorset( BerElement *ber, ber_tag_t tag )
+{
+	Seqorset	*new_sos;
+
+	/* can we fit into the local stack ? */
+	if (ber->ber_sos_stack_posn < SOS_STACK_SIZE) {
+		/* yes */
+		new_sos = &ber->ber_sos_stack[ber->ber_sos_stack_posn];
+	} else {
+		/* no */
+		if ( (new_sos = (Seqorset *)NSLBERI_MALLOC( sizeof(Seqorset)))
+		    == NULLSEQORSET ) {
+			return( -1 );
+		}
+	}
+	ber->ber_sos_stack_posn++;
+
+	if ( ber->ber_sos == NULLSEQORSET )
+		new_sos->sos_first = ber->ber_ptr;
+	else
+		new_sos->sos_first = ber->ber_sos->sos_ptr;
+
+	/* Set aside room for a 4 byte length field */
+	new_sos->sos_ptr = new_sos->sos_first + ber_calc_taglen( tag ) + FOUR_BYTE_LEN;
+	new_sos->sos_tag = tag;
+
+	new_sos->sos_next = ber->ber_sos;
+	new_sos->sos_clen = 0;
+
+	ber->ber_sos = new_sos;
+    if (ber->ber_sos->sos_ptr > ber->ber_end) {
+        nslberi_ber_realloc(ber, ber->ber_sos->sos_ptr - ber->ber_end);
+    }
+	return( 0 );
+}
+
+int
+LDAP_CALL
+ber_start_seq( BerElement *ber, ber_tag_t tag )
+{
+	if ( tag == LBER_DEFAULT )
+		tag = LBER_SEQUENCE;
+
+	return( ber_start_seqorset( ber, tag ) );
+}
+
+int
+LDAP_CALL
+ber_start_set( BerElement *ber, ber_tag_t tag )
+{
+	if ( tag == LBER_DEFAULT )
+		tag = LBER_SET;
+
+	return( ber_start_seqorset( ber, tag ) );
+}
+
+static int
+ber_put_seqorset( BerElement *ber )
+{
+	ber_len_t		len, netlen;
+	int				taglen, lenlen;
+	unsigned char	ltag = 0x80 + FOUR_BYTE_LEN - 1;
+	Seqorset		*next;
+	Seqorset		**sos = &ber->ber_sos;
+
+	if ( *sos == NULL ) {
+        /* No sequence or set to put... fatal error. */
+        return( -1 );
+	}
+
+    /*
+	 * If this is the toplevel sequence or set, we need to actually
+	 * write the stuff out.  Otherwise, it's already been put in
+	 * the appropriate buffer and will be written when the toplevel
+	 * one is written.  In this case all we need to do is update the
+	 * length and tag.
+	 */
+
+	len = (*sos)->sos_clen;
+	netlen = LBER_HTONL( len );
+	if ( sizeof(ber_int_t) > 4 && len > 0xFFFFFFFF )
+		return( -1 );
+
+	if ( ber->ber_options & LBER_OPT_USE_DER ) {
+		lenlen = ber_calc_lenlen( len );
+	} else {
+		lenlen = FOUR_BYTE_LEN;
+	}
+
+	if ( (next = (*sos)->sos_next) == NULLSEQORSET ) {
+		/* write the tag */
+		if ( (taglen = ber_put_tag( ber, (*sos)->sos_tag, 1 )) == -1 )
+			return( -1 );
+
+		if ( ber->ber_options & LBER_OPT_USE_DER ) {
+			/* Write the length in the minimum # of octets */
+			if ( ber_put_len( ber, len, 1 ) == -1 )
+				return( -1 );
+
+			if (lenlen != FOUR_BYTE_LEN) {
+				/*
+				 * We set aside FOUR_BYTE_LEN bytes for
+				 * the length field.  Move the data if
+				 * we don't actually need that much
+				 */
+				SAFEMEMCPY( (*sos)->sos_first + taglen +
+				    lenlen, (*sos)->sos_first + taglen +
+				    FOUR_BYTE_LEN, len );
+			}
+		} else {
+			/* Fill FOUR_BYTE_LEN bytes for length field */
+			/* one byte of length length */
+			if ( ber_write( ber, (char *)&ltag, 1, 1 ) != 1 )
+				return( -1 );
+
+			/* the length itself */
+			if ( ber_write( ber, (char *) &netlen + sizeof(ber_int_t)
+			    - (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1, 1 )
+			    != FOUR_BYTE_LEN - 1 )
+				return( -1 );
+		}
+		/* The ber_ptr is at the set/seq start - move it to the end */
+		ber->ber_ptr += len;
+	} else {
+		ber_tag_t	ntag;
+
+		/* the tag */
+		taglen = ber_calc_taglen( (*sos)->sos_tag );
+		ntag = LBER_HTONL( (*sos)->sos_tag );
+		SAFEMEMCPY( (*sos)->sos_first, (char *) &ntag +
+		    sizeof(ber_int_t) - taglen, taglen );
+
+		if ( ber->ber_options & LBER_OPT_USE_DER ) {
+			ltag = (lenlen == 1) ? (unsigned char)len :  
+                (unsigned char) (0x80 + (lenlen - 1));
+		}
+
+		/* one byte of length length */
+		SAFEMEMCPY( (*sos)->sos_first + 1, &ltag, 1 );
+
+		if ( ber->ber_options & LBER_OPT_USE_DER ) {
+			if (lenlen > 1) {
+				/* Write the length itself */
+				SAFEMEMCPY( (*sos)->sos_first + 2,
+				    (char *)&netlen + sizeof(ber_uint_t) -
+				    (lenlen - 1),
+				    lenlen - 1 );
+			}
+			if (lenlen != FOUR_BYTE_LEN) {
+				/*
+				 * We set aside FOUR_BYTE_LEN bytes for
+				 * the length field.  Move the data if
+				 * we don't actually need that much
+				 */
+				SAFEMEMCPY( (*sos)->sos_first + taglen +
+				    lenlen, (*sos)->sos_first + taglen +
+				    FOUR_BYTE_LEN, len );
+			}
+		} else {
+			/* the length itself */
+			SAFEMEMCPY( (*sos)->sos_first + taglen + 1,
+			    (char *) &netlen + sizeof(ber_int_t) -
+			    (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1 );
+		}
+
+		next->sos_clen += (taglen + lenlen + len);
+		next->sos_ptr += (taglen + lenlen + len);
+	}
+
+	/* we're done with this seqorset, so free it up */
+	/* was this one from the local stack ? */
+	if (ber->ber_sos_stack_posn <= SOS_STACK_SIZE) {
+		/* yes */
+	} else {
+		/* no */
+		NSLBERI_FREE( (char *) (*sos) );
+	}
+	ber->ber_sos_stack_posn--;
+	*sos = next;
+
+	return( taglen + lenlen + len );
+}
+
+int
+LDAP_CALL
+ber_put_seq( BerElement *ber )
+{
+	return( ber_put_seqorset( ber ) );
+}
+
+int
+LDAP_CALL
+ber_put_set( BerElement *ber )
+{
+	return( ber_put_seqorset( ber ) );
+}
+
+/* VARARGS */
+int
+LDAP_C
+ber_printf( BerElement *ber, const char *fmt, ... )
+{
+	va_list			ap;
+	char			*s, **ss;
+	struct berval	*bval, **bv;
+	int				rc, i;
+	ber_len_t		len;
+
+	va_start( ap, fmt );
+
+#ifdef LDAP_DEBUG
+	if ( lber_debug & 64 ) {
+		char msg[80];
+		sprintf( msg, "ber_printf fmt (%s)\n", fmt );
+		ber_err_print( msg );
+	}
+#endif
+
+	for ( rc = 0; *fmt && rc != -1; fmt++ ) {
+		switch ( *fmt ) {
+		case 'b':	/* boolean */
+			i = va_arg( ap, int );
+			rc = ber_put_boolean( ber, i, ber->ber_tag );
+			break;
+
+		case 'i':	/* int */
+			i = va_arg( ap, int );
+			rc = ber_put_int( ber, (ber_int_t)i, ber->ber_tag );
+			break;
+
+		case 'e':	/* enumeration */
+			i = va_arg( ap, int );
+			rc = ber_put_enum( ber, (ber_int_t)i, ber->ber_tag );
+			break;
+
+		case 'n':	/* null */
+			rc = ber_put_null( ber, ber->ber_tag );
+			break;
+
+		case 'o':	/* octet string (non-null terminated) */
+			s = va_arg( ap, char * );
+			len = va_arg( ap, int );
+			rc = ber_put_ostring( ber, s, len, ber->ber_tag );
+			break;
+
+		case 'O':	/* berval octet string */
+			if( ( bval = va_arg( ap, struct berval * ) ) == NULL )
+				break;
+			if( bval->bv_len == 0 ) {
+				rc = ber_put_ostring( ber, "", 0, ber->ber_tag );
+			} else {
+				rc = ber_put_ostring( ber, bval->bv_val, bval->bv_len,
+					ber->ber_tag );
+			}
+ 			break;
+
+		case 's':	/* string */
+			s = va_arg( ap, char * );
+			rc = ber_put_string( ber, s, ber->ber_tag );
+			break;
+
+		case 'B':	/* bit string */
+			s = va_arg( ap, char * );
+			len = va_arg( ap, int );	/* in bits */
+			rc = ber_put_bitstring( ber, s, len, ber->ber_tag );
+			break;
+
+		case 't':	/* tag for the next element */
+			ber->ber_tag = va_arg( ap, ber_tag_t );
+			ber->ber_usertag = 1;
+			break;
+
+		case 'v':	/* vector of strings */
+			if ( (ss = va_arg( ap, char ** )) == NULL )
+				break;
+			for ( i = 0; ss[i] != NULL; i++ ) {
+				if ( (rc = ber_put_string( ber, ss[i],
+				    ber->ber_tag )) == -1 )
+					break;
+			}
+			break;
+
+		case 'V':	/* sequences of strings + lengths */
+			if ( (bv = va_arg( ap, struct berval ** )) == NULL )
+				break;
+			for ( i = 0; bv[i] != NULL; i++ ) {
+				if ( (rc = ber_put_ostring( ber, bv[i]->bv_val,
+				    bv[i]->bv_len, ber->ber_tag )) == -1 )
+					break;
+			}
+			break;
+
+		case '{':	/* begin sequence */
+			rc = ber_start_seq( ber, ber->ber_tag );
+			break;
+
+		case '}':	/* end sequence */
+			rc = ber_put_seqorset( ber );
+			break;
+
+		case '[':	/* begin set */
+			rc = ber_start_set( ber, ber->ber_tag );
+			break;
+
+		case ']':	/* end set */
+			rc = ber_put_seqorset( ber );
+			break;
+
+		default: {
+				char msg[80];
+				sprintf( msg, "unknown fmt %c\n", *fmt );
+				ber_err_print( msg );
+				rc = -1;
+				break;
+			}
+		}
+
+		if ( ber->ber_usertag == 0 )
+			ber->ber_tag = LBER_DEFAULT;
+		else
+			ber->ber_usertag = 0;
+	}
+
+	va_end( ap );
+
+	return( rc );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/liblber/etest.c
@@ -0,0 +1,193 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+/* test.c - lber encoding test program */
+
+#include <stdio.h>
+#include <string.h>
+#ifdef MACOS
+#include <stdlib.h>
+#include <unix.h>
+#include <fcntl.h>
+#include <console.h>
+#else /* MACOS */
+#include <sys/types.h>
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <sys/socket.h>
+#endif /* _WIN32 */
+#endif /* MACOS */
+#include "lber.h"
+
+int
+SSL_Recv( int s, char *b, unsigned l, int dummy )
+{
+	return( read( s, b, l ) );
+}
+
+SSL_Send( int s, char *b, unsigned l, int dummy )
+{
+	return( write( s, b, l ) );
+}
+
+int
+getline( char *prompt, char c, char *buf, int bsize )
+{
+	char	*p;
+
+	if ( prompt != NULL ) {
+		fprintf( stderr, "%s: ", prompt );
+	} else {
+		fprintf( stderr, "enter value for '%c': ", c );
+	}
+	if ( fgets( buf, bsize, stdin ) == NULL ) {
+		return( -1 );
+	}
+	if ( (p = strchr( buf, '\n' )) != NULL ) {
+		*p = '\0';
+	}
+
+	return( 0 );
+}
+
+
+static void usage( char *name )
+{
+	fprintf( stderr, "usage: %s fmtstring\n", name );
+}
+
+main( int argc, char **argv )
+{
+	int		rc, fd;
+	char		*s, *p;
+	void		*arg1, *arg2;
+	Sockbuf		*sb;
+	BerElement	*ber;
+	char		fmt[2];
+	char		buf[BUFSIZ];
+	extern int	lber_debug;
+
+	lber_debug = 255;
+	if ( argc < 2 ) {
+		usage( argv[0] );
+		exit( 1 );
+	}
+
+	sb = ber_sockbuf_alloc();
+	fd = 1;
+	ber_sockbuf_set_option( sb, LBER_SOCKBUF_OPT_DESC, &fd );
+
+	if ( (ber = der_alloc()) == NULL ) {
+		perror( "ber_alloc" );
+		exit( 1 );
+	}
+
+	rc = 0;
+	fmt[1] = '\0';
+	for ( s = argv[1]; *s; s++ ) {
+		switch ( *s ) {
+		case 'i':	/* int */
+		case 'b':	/* boolean */
+		case 'e':	/* enumeration */
+			getline( NULL, *s, buf, sizeof(buf) );
+			arg1 = (void *) atoi( buf );
+			break;
+
+		case 'n':	/* null */
+			arg1 = NULL;
+			break;
+
+		case 'o':	/* octet string (non-null terminated) */
+			getline( NULL, *s, buf, sizeof(buf) );
+			arg1 = (void *) buf;
+			arg2 = (void *) strlen( buf );
+			break;
+
+		case 's':	/* string */
+			getline( NULL, *s, buf, sizeof(buf) );
+			arg1 = (void *) buf;
+			break;
+
+		case 'B':	/* bit string */
+			getline( NULL, *s, buf, sizeof(buf) );
+			arg1 = (void *) buf;
+			arg2 = (void *) strlen( buf );
+			break;
+
+		case 't':	/* tag for the next element */
+			getline( NULL, *s, buf, sizeof(buf) );
+			arg1 = (void *) buf;
+			break;
+
+		case '{':	/* begin sequence */
+		case '}':	/* end sequence */
+		case '[':	/* begin set */
+		case ']':	/* end set */
+			break;
+
+		default:
+			fprintf( stderr, "unknown fmt %c\n", *s );
+			rc = -1;
+			break;
+		}
+
+		fmt[0] = *s;
+		if ( ber_printf( ber, fmt, arg1, arg2 ) == -1 ) {
+			fprintf( stderr, "ber_printf\n" );
+			exit( 1 );
+		}
+	}
+
+	if ( ber_flush( sb, ber, 1 ) != 0 ) {
+		perror( "ber_flush" );
+		rc = -1;
+	}
+
+	return( rc );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/liblber/idtest.c
@@ -0,0 +1,100 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+/* idtest.c - ber decoding test program using isode libraries */
+
+#include <stdio.h>
+#include <psap.h>
+#include <quipu/attr.h>
+
+static usage( char *name )
+{
+	fprintf( stderr, "usage: %s\n", name );
+}
+
+main( int argc, char **argv )
+{
+	PE	pe;
+	PS	psin, psout, pserr;
+
+	/* read the pe from standard in */
+	if ( (psin = ps_alloc( std_open )) == NULLPS ) {
+		perror( "ps_alloc" );
+		exit( 1 );
+	}
+	if ( std_setup( psin, stdin ) == NOTOK ) {
+		perror( "std_setup" );
+		exit( 1 );
+	}
+	/* write the pe to standard out */
+	if ( (psout = ps_alloc( std_open )) == NULLPS ) {
+		perror( "ps_alloc" );
+		exit( 1 );
+	}
+	if ( std_setup( psout, stdout ) == NOTOK ) {
+		perror( "std_setup" );
+		exit( 1 );
+	}
+	/* pretty print it to standard error */
+	if ( (pserr = ps_alloc( std_open )) == NULLPS ) {
+		perror( "ps_alloc" );
+		exit( 1 );
+	}
+	if ( std_setup( pserr, stderr ) == NOTOK ) {
+		perror( "std_setup" );
+		exit( 1 );
+	}
+
+	while ( (pe = ps2pe( psin )) != NULLPE ) {
+		pe2pl( pserr, pe );
+		pe2ps( psout, pe );
+	}
+
+	exit( 0 );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/liblber/io.c
@@ -0,0 +1,1757 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+/* io.c - ber general i/o routines */
+
+#include "lber-int.h"
+
+#define bergetc( sb, len )    ( sb->sb_ber.ber_end > sb->sb_ber.ber_ptr ? \
+			  (unsigned char)*sb->sb_ber.ber_ptr++ : \
+			  ber_filbuf( sb, len ))
+
+# ifdef macintosh
+/*
+ * MacTCP/OpenTransport
+ */
+#  define read( s, b, l ) tcpread( s, 0, (unsigned char *)b, l, NULL )
+#  define MAX_WRITE	65535
+#  define BerWrite( sb, b, l )   tcpwrite( sb->sb_sd, (unsigned char *)(b), (l<MAX_WRITE)? l : MAX_WRITE )
+# else /* macintosh */
+#  if defined(_WIN32) || defined(_WINDOWS) || defined(XP_OS2)
+/*
+ * 32-bit Windows Socket API (under Windows NT or Windows 95)
+ */
+#   define read( s, b, l )		recv( s, b, l, 0 )
+#   define BerWrite( s, b, l )	send( s->sb_sd, b, l, 0 )
+#  else /* _WIN32 */
+/*
+ * everything else (Unix/BSD 4.3 socket API)
+ */
+#   define BerWrite( sb, b, l )	write( sb->sb_sd, b, l )
+#   define udp_read( sb, b, l, al ) recvfrom(sb->sb_sd, (char *)b, l, 0, \
+		(struct sockaddr *)sb->sb_fromaddr, \
+		(al = sizeof(struct sockaddr), &al))
+#   define udp_write( sb, b, l ) sendto(sb->sb_sd, (char *)(b), l, 0, \
+		(struct sockaddr *)sb->sb_useaddr, sizeof(struct sockaddr))
+#  endif /* _WIN32 */
+# endif /* macintosh */
+
+#ifndef udp_read
+#define udp_read( sb, b, l, al )	CLDAP NOT SUPPORTED
+#define udp_write( sb, b, l )		CLDAP NOT SUPPORTED
+#endif /* udp_read */
+
+#define EXBUFSIZ			1024
+size_t  lber_bufsize = EXBUFSIZ;
+
+#ifdef LDAP_DEBUG
+int	lber_debug;
+#endif
+
+/*
+ * function prototypes
+ */
+static void nslberi_install_compat_io_fns( Sockbuf *sb );
+static int nslberi_extread_compat( int s, void *buf, int len,
+		struct lextiof_socket_private *arg );
+static int nslberi_extwrite_compat( int s, const void *buf, int len,
+		struct lextiof_socket_private *arg );
+static ber_tag_t get_tag( Sockbuf *sb, BerElement *ber);
+static ber_len_t get_ber_len( BerElement *ber);
+static ber_len_t read_len_in_ber( Sockbuf *sb, BerElement *ber);
+
+/*
+ * internal global structure for memory allocation callback functions
+ */
+static struct lber_memalloc_fns nslberi_memalloc_fns;
+
+
+/*
+ * buffered read from "sb".
+ * returns value of first character read on success and -1 on error.
+ */
+static int
+ber_filbuf( Sockbuf *sb, ber_slen_t len )
+{
+	ssize_t	rc;
+#ifdef CLDAP
+	int	addrlen;
+#endif /* CLDAP */
+
+	if ( sb->sb_ber.ber_buf == NULL ) {
+		if ( (sb->sb_ber.ber_buf = (char *)NSLBERI_MALLOC(
+		    READBUFSIZ )) == NULL ) {
+			return( -1 );
+		}
+		sb->sb_ber.ber_flags &= ~LBER_FLAG_NO_FREE_BUFFER;
+		sb->sb_ber.ber_ptr = sb->sb_ber.ber_buf;
+		sb->sb_ber.ber_end = sb->sb_ber.ber_buf;
+	}
+
+	if ( sb->sb_naddr > 0 ) {
+#ifdef CLDAP
+		rc = udp_read(sb, sb->sb_ber.ber_buf, READBUFSIZ, addrlen );
+#ifdef LDAP_DEBUG
+		if ( lber_debug ) {
+			char msg[80];
+			sprintf( msg, "ber_filbuf udp_read %d bytes\n",
+				rc );
+			ber_err_print( msg );
+			if ( lber_debug > 1 && rc > 0 )
+				lber_bprint( sb->sb_ber.ber_buf, rc );
+		}
+#endif /* LDAP_DEBUG */
+#else /* CLDAP */
+		rc = -1;
+#endif /* CLDAP */
+	} else {
+		if ( sb->sb_ext_io_fns.lbextiofn_read != NULL ) {
+			rc = sb->sb_ext_io_fns.lbextiofn_read(
+			    sb->sb_sd, sb->sb_ber.ber_buf,
+			    ((sb->sb_options & LBER_SOCKBUF_OPT_NO_READ_AHEAD)
+			    && (len < READBUFSIZ)) ? len : READBUFSIZ,
+			    sb->sb_ext_io_fns.lbextiofn_socket_arg );
+		} else {
+#ifdef NSLDAPI_AVOID_OS_SOCKETS
+			return( -1 );
+#else
+			rc = read( sb->sb_sd, sb->sb_ber.ber_buf,
+			    ((sb->sb_options & LBER_SOCKBUF_OPT_NO_READ_AHEAD)
+			    && (len < READBUFSIZ)) ? len : READBUFSIZ );
+#endif
+		}
+	}
+
+	if ( rc > 0 ) {
+		sb->sb_ber.ber_ptr = sb->sb_ber.ber_buf + 1;
+		sb->sb_ber.ber_end = sb->sb_ber.ber_buf + rc;
+		return( (unsigned char)*sb->sb_ber.ber_buf );
+	}
+
+	return( -1 );
+}
+
+
+static ber_int_t
+BerRead( Sockbuf *sb, char *buf, ber_slen_t len )
+{
+  int c;
+  ber_int_t nread = 0;
+  
+  while (len > 0)
+    {
+      ber_int_t inberbuf = sb->sb_ber.ber_end - sb->sb_ber.ber_ptr;
+      if (inberbuf > 0)
+	{
+	  size_t tocopy = len > inberbuf ? inberbuf : len;
+	  SAFEMEMCPY(buf, sb->sb_ber.ber_ptr, tocopy);
+	  buf += tocopy;
+	  sb->sb_ber.ber_ptr += tocopy;
+	  nread += tocopy;
+	  len -= tocopy;
+	}
+      else
+	{
+	  c = ber_filbuf(sb, len);
+	  if (c < 0)
+	    {
+	      if (nread > 0)
+		break;
+               else
+                 return c;
+             }
+           *buf++ = c;
+           nread++;
+           len--;
+         }
+     }
+   return (nread);
+}
+
+
+/*
+ * Note: ber_read() only uses the ber_end and ber_ptr elements of ber.
+ * Functions like ber_get_tag(), ber_skip_tag, and ber_peek_tag() rely on
+ * that fact, so if this code is changed to use any additional elements of
+ * the ber structure, those functions will need to be changed as well.
+ */
+ber_int_t
+LDAP_CALL
+ber_read( BerElement *ber, char *buf, ber_len_t len )
+{
+	ber_len_t	actuallen;
+	ber_uint_t  nleft;
+
+	nleft = ber->ber_end - ber->ber_ptr;
+	actuallen = nleft < len ? nleft : len;
+
+	SAFEMEMCPY( buf, ber->ber_ptr, (size_t)actuallen );
+
+	ber->ber_ptr += actuallen;
+
+	return( (ber_int_t)actuallen );
+}
+
+/*
+ * enlarge the ber buffer.
+ * return 0 on success, -1 on error.
+ */
+int
+nslberi_ber_realloc( BerElement *ber, ber_len_t len )
+{
+	ber_uint_t	need, have, total;
+	size_t		have_bytes;
+	Seqorset	*s;
+	ber_int_t	off;
+	char		*oldbuf;
+	int			freeoldbuf = 0;
+
+	ber->ber_buf_reallocs++;
+
+	have_bytes = ber->ber_end - ber->ber_buf;
+	have = have_bytes / lber_bufsize;
+	need = (len < lber_bufsize ? 1 : (len + (lber_bufsize - 1)) / lber_bufsize);
+	total = have * lber_bufsize + need * lber_bufsize * ber->ber_buf_reallocs;
+	
+	oldbuf = ber->ber_buf;
+
+	if (ber->ber_buf == NULL) {
+		if ( (ber->ber_buf = (char *)NSLBERI_MALLOC( (size_t)total ))
+			 == NULL ) {
+			return( -1 );
+		}
+		ber->ber_flags &= ~LBER_FLAG_NO_FREE_BUFFER;
+	} else {
+		if ( !(ber->ber_flags & LBER_FLAG_NO_FREE_BUFFER) ) {
+			freeoldbuf = 1;
+		}
+		/* transition to malloc'd buffer */
+		if ( (ber->ber_buf = (char *)NSLBERI_MALLOC(
+			(size_t)total )) == NULL ) {
+			return( -1 );
+		}
+		ber->ber_flags &= ~LBER_FLAG_NO_FREE_BUFFER;
+		/* copy existing data into new malloc'd buffer */
+		SAFEMEMCPY( ber->ber_buf, oldbuf, have_bytes );
+	}
+
+	ber->ber_end = ber->ber_buf + total;
+
+	/*
+	 * If the stinking thing was moved, we need to go through and
+	 * reset all the sos and ber pointers.  Offsets would've been
+	 * a better idea... oh well.
+	 */
+
+	if ( ber->ber_buf != oldbuf ) {	
+		ber->ber_ptr = ber->ber_buf + (ber->ber_ptr - oldbuf);
+
+		for ( s = ber->ber_sos; s != NULLSEQORSET; s = s->sos_next ) {
+			off = s->sos_first - oldbuf;
+			s->sos_first = ber->ber_buf + off;
+
+			off = s->sos_ptr - oldbuf;
+			s->sos_ptr = ber->ber_buf + off;
+		}
+		
+		if ( freeoldbuf && oldbuf ) {
+			NSLBERI_FREE( oldbuf );
+		}
+	}
+
+	return( 0 );
+}
+
+/*
+ * returns "len" on success and -1 on failure.
+ */
+ber_int_t
+LDAP_CALL
+ber_write( BerElement *ber, char *buf, ber_len_t len, int nosos )
+{
+	if ( nosos || ber->ber_sos == NULL ) {
+		if ( ber->ber_ptr + len > ber->ber_end ) {
+			if ( nslberi_ber_realloc( ber, len ) != 0 )
+				return( -1 );
+		}
+		SAFEMEMCPY( ber->ber_ptr, buf, (size_t)len );
+		ber->ber_ptr += len;
+		return( len );
+	} else {
+		if ( ber->ber_sos->sos_ptr + len > ber->ber_end ) {
+			if ( nslberi_ber_realloc( ber, len ) != 0 )
+				return( -1 );
+		}
+		SAFEMEMCPY( ber->ber_sos->sos_ptr, buf, (size_t)len );
+		ber->ber_sos->sos_ptr += len;
+		ber->ber_sos->sos_clen += len;
+		return( len );
+	}
+}
+
+void
+LDAP_CALL
+ber_free( BerElement *ber, int freebuf )
+{
+	if ( ber != NULL ) {
+		    if ( freebuf &&
+			!(ber->ber_flags & LBER_FLAG_NO_FREE_BUFFER)) {
+			    NSLBERI_FREE(ber->ber_buf);
+		    }
+		    NSLBERI_FREE( (char *) ber );
+	}
+}
+
+/*
+ * return >= 0 on success, -1 on failure.
+ */
+int
+LDAP_CALL
+ber_flush( Sockbuf *sb, BerElement *ber, int freeit )
+{
+	ssize_t	nwritten = 0, towrite, rc;
+	int     i = 0;
+	
+	if (ber->ber_rwptr == NULL) {
+	  ber->ber_rwptr = ber->ber_buf;
+	} else if (ber->ber_rwptr >= ber->ber_end) {
+	  /* we will use the ber_rwptr to continue an exited flush,
+	     so if rwptr is not within the buffer we return an error. */
+	  return( -1 );
+	}
+	
+	/* writev section - for iDAR only!!! */
+	if (sb->sb_ext_io_fns.lbextiofn_writev != NULL) {
+
+	  /* add the sizes of the different buffers to write with writev */
+	  for (towrite = 0, i = 0; i < BER_ARRAY_QUANTITY; ++i) {
+	    /* don't add lengths of null buffers - writev will ignore them */
+	    if (ber->ber_struct[i].ldapiov_base) {
+	      towrite += ber->ber_struct[i].ldapiov_len;
+	    }
+	  }
+	  
+	  rc = sb->sb_ext_io_fns.lbextiofn_writev(sb->sb_sd, ber->ber_struct, BER_ARRAY_QUANTITY, 
+						  sb->sb_ext_io_fns.lbextiofn_socket_arg);
+	  
+	  if ( freeit )
+		ber_free( ber, 1 );
+
+	  if (rc >= 0) {
+	    /* return the number of bytes TO BE written */
+	    return (towrite - rc);
+	  } else {
+	    /* otherwise it's an error */
+	    return (rc);
+	  }
+	} /* end writev section */
+
+	towrite = ber->ber_ptr - ber->ber_rwptr;
+
+#ifdef LDAP_DEBUG
+	if ( lber_debug ) {
+		char msg[80];
+		sprintf( msg, "ber_flush: %d bytes to sd %ld%s\n", (int)towrite,
+		    sb->sb_sd, ber->ber_rwptr != ber->ber_buf ? " (re-flush)"
+		    : "" );
+		ber_err_print( msg );
+		if ( lber_debug > 1 )
+			lber_bprint( ber->ber_rwptr, towrite );
+	}
+#endif
+#if !defined(macintosh) && !defined(DOS)
+	if ( sb->sb_options & (LBER_SOCKBUF_OPT_TO_FILE | LBER_SOCKBUF_OPT_TO_FILE_ONLY) ) {
+		rc = write( sb->sb_copyfd, ber->ber_buf, towrite );
+		if ( sb->sb_options & LBER_SOCKBUF_OPT_TO_FILE_ONLY ) {
+			return( (int)rc );
+		}
+	}
+#endif
+
+	nwritten = 0;
+	do {
+		if (sb->sb_naddr > 0) {
+#ifdef CLDAP
+			rc = udp_write( sb, ber->ber_buf + nwritten,
+			    (size_t)towrite );
+#else /* CLDAP */
+			rc = -1;
+#endif /* CLDAP */
+			if ( rc <= 0 )
+				return( -1 );
+			/* fake error if write was not atomic */
+			if (rc < towrite) {
+#if !defined( macintosh ) && !defined( DOS )
+			    errno = EMSGSIZE;  /* For Win32, see portable.h */
+#endif
+			    return( -1 );
+			}
+		} else {
+			if ( sb->sb_ext_io_fns.lbextiofn_write != NULL ) {
+				if ( (rc = sb->sb_ext_io_fns.lbextiofn_write(
+				    sb->sb_sd, ber->ber_rwptr, (size_t)towrite,
+				    sb->sb_ext_io_fns.lbextiofn_socket_arg ))
+				    <= 0 ) {
+					return( -1 );
+				}
+			} else {
+#ifdef NSLDAPI_AVOID_OS_SOCKETS
+				return( -1 );
+#else
+				if ( (rc = BerWrite( sb, ber->ber_rwptr,
+				    (size_t) towrite )) <= 0 ) {
+					return( -1 );
+				}
+#endif
+			}
+		}
+		towrite -= rc;
+		nwritten += rc;
+		ber->ber_rwptr += rc;
+	} while ( towrite > 0 );
+
+	if ( freeit )
+		ber_free( ber, 1 );
+
+	return( 0 );
+}
+
+
+/* we pre-allocate a buffer to save the extra malloc later */
+BerElement *
+LDAP_CALL
+ber_alloc_t( int options )
+{
+	BerElement	*ber;
+
+	if ( (ber = (BerElement*)NSLBERI_CALLOC( 1,
+	    sizeof(struct berelement) + lber_bufsize )) == NULL ) {
+		return( NULL );
+	}
+
+	/*
+	 * for compatibility with the C LDAP API standard, we recognize
+	 * LBER_USE_DER as LBER_OPT_USE_DER.  See lber.h for a bit more info.
+	 */
+	if ( options & LBER_USE_DER ) {
+		options &= ~LBER_USE_DER;
+		options |= LBER_OPT_USE_DER;
+	}
+
+	ber->ber_tag = LBER_DEFAULT;
+	ber->ber_options = options;
+	ber->ber_buf = (char*)ber + sizeof(struct berelement);
+	ber->ber_ptr = ber->ber_buf;
+	ber->ber_end = ber->ber_buf + lber_bufsize;
+	ber->ber_flags = LBER_FLAG_NO_FREE_BUFFER;
+
+	return( ber );
+}
+
+
+BerElement *
+LDAP_CALL
+ber_alloc()
+{
+	return( ber_alloc_t( 0 ) );
+}
+
+BerElement *
+LDAP_CALL
+der_alloc()
+{
+	return( ber_alloc_t( LBER_OPT_USE_DER ) );
+}
+
+BerElement *
+LDAP_CALL
+ber_dup( BerElement *ber )
+{
+	BerElement	*new;
+
+	if ( (new = ber_alloc()) == NULL )
+		return( NULL );
+
+	*new = *ber;
+
+	return( new );
+}
+
+
+void
+LDAP_CALL
+ber_init_w_nullchar( BerElement *ber, int options )
+{
+	(void) memset( (char *)ber, '\0', sizeof(struct berelement) );
+	ber->ber_tag = LBER_DEFAULT;
+
+	/*
+	 * For compatibility with the C LDAP API standard, we recognize
+	 * LBER_USE_DER as LBER_OPT_USE_DER.  See lber.h for a bit more info.
+	 */
+	if ( options & LBER_USE_DER ) {
+		options &= ~LBER_USE_DER;
+		options |= LBER_OPT_USE_DER;
+	}
+
+	ber->ber_options = options;
+}
+
+void
+LDAP_CALL
+ber_reset( BerElement *ber, int was_writing )
+{
+	if ( was_writing ) {
+		ber->ber_end = ber->ber_ptr;
+		ber->ber_ptr = ber->ber_buf;
+	} else {
+		ber->ber_ptr = ber->ber_end;
+	}
+
+	ber->ber_rwptr = NULL;
+	ber->ber_tag_len_read = 0;
+
+	memset(ber->ber_struct, 0, BER_CONTENTS_STRUCT_SIZE);
+}
+
+/* Returns the length of the ber buffer so far,
+   taking into account sequences/sets also.
+   CAUTION: Returns 0 on null buffers as well 
+   as 0 on empty buffers!
+*/
+size_t
+LDAP_CALL
+ber_get_buf_datalen( BerElement *ber )
+{
+  size_t datalen;
+
+  if ( ( ber == NULL) || ( ber->ber_buf == NULL) || ( ber->ber_ptr == NULL ) ) {
+    datalen = 0;
+  } else if (ber->ber_sos == NULLSEQORSET) {
+    /* there are no sequences or sets yet, 
+       so just subtract ptr from the beginning of the ber buffer */
+    datalen = ber->ber_ptr - ber->ber_buf;
+  } else {
+    /* sequences exist, so just take the ptr of the sequence
+       on top of the stack and subtract the beginning of the
+       buffer from it */
+    datalen = ber->ber_sos->sos_ptr - ber->ber_buf;
+  }
+  
+  return datalen;
+}
+
+/*
+  if buf is 0 then malloc a buffer of length size
+  returns > 0 on success, 0 otherwise
+*/
+int
+LDAP_CALL
+ber_stack_init(BerElement *ber, int options, char * buf,
+        size_t size)
+{
+  if (NULL == ber)
+    return 0;
+  
+  memset(ber, 0, sizeof(*ber));
+
+  /*
+   * for compatibility with the C LDAP API standard, we recognize
+   * LBER_USE_DER as LBER_OPT_USE_DER.  See lber.h for a bit more info.
+   */
+
+  if ( options & LBER_USE_DER ) {
+    options &= ~LBER_USE_DER;
+    options |= LBER_OPT_USE_DER;
+  }
+
+  ber->ber_tag = LBER_DEFAULT;
+  ber->ber_options = options;
+  
+  if ( ber->ber_buf && !(ber->ber_flags & LBER_FLAG_NO_FREE_BUFFER)) {
+	  NSLBERI_FREE(ber->ber_buf);
+  }
+  
+  if (buf) {
+    ber->ber_buf = ber->ber_ptr = buf;
+    ber->ber_flags = LBER_FLAG_NO_FREE_BUFFER;
+  } else {
+    ber->ber_buf = ber->ber_ptr = (char *) NSLBERI_MALLOC(size);
+  }
+
+  ber->ber_end = ber->ber_buf + size;
+
+  return ber->ber_buf != 0;
+}
+
+/*
+ * This call allows to release only the data part of
+ * the target Sockbuf.
+ * Other info of this Sockbuf are kept unchanged.
+ */
+void
+LDAP_CALL
+ber_sockbuf_free_data(Sockbuf *p)
+{
+    if ( p != NULL ) {
+	if ( p->sb_ber.ber_buf != NULL &&
+	     !(p->sb_ber.ber_flags & LBER_FLAG_NO_FREE_BUFFER) ) {
+	    NSLBERI_FREE( p->sb_ber.ber_buf );
+	    p->sb_ber.ber_buf = NULL;
+	}
+    }
+}
+
+/* simply returns ber_buf in the ber ...
+   explicitly for DS MMR only...
+*/
+char *
+LDAP_CALL
+ber_get_buf_databegin (BerElement * ber)
+{
+  if (NULL != ber) {
+    return ber->ber_buf;
+  } else {
+    return NULL;
+  }
+}
+
+#ifdef LDAP_DEBUG
+
+void
+ber_dump( BerElement *ber, int inout )
+{
+	char msg[128];
+	sprintf( msg, "ber_dump: buf 0x%p, ptr 0x%p, rwptr 0x%p, end 0x%p\n",
+	    ber->ber_buf, ber->ber_ptr, ber->ber_rwptr, ber->ber_end );
+	ber_err_print( msg );
+	if ( inout == 1 ) {
+		sprintf( msg, "          current len %ld, contents:\n",
+                 (long)(ber->ber_end - ber->ber_ptr) );
+		ber_err_print( msg );
+		lber_bprint( ber->ber_ptr, ber->ber_end - ber->ber_ptr );
+	} else {
+		sprintf( msg, "          current len %ld, contents:\n",
+                 (long)(ber->ber_ptr - ber->ber_buf) );
+		ber_err_print( msg );
+		lber_bprint( ber->ber_buf, ber->ber_ptr - ber->ber_buf );
+	}
+}
+
+void
+ber_sos_dump( Seqorset *sos )
+{
+	char msg[80];
+	ber_err_print ( "*** sos dump ***\n" );
+	while ( sos != NULLSEQORSET ) {
+		sprintf( msg, "ber_sos_dump: clen %d first 0x%p ptr 0x%p\n",
+		    sos->sos_clen, sos->sos_first, sos->sos_ptr );
+		ber_err_print( msg );
+		sprintf( msg, "              current len %ld contents:\n",
+                 (long)(sos->sos_ptr - sos->sos_first) );
+		ber_err_print( msg );
+		lber_bprint( sos->sos_first, sos->sos_ptr - sos->sos_first );
+
+		sos = sos->sos_next;
+	}
+	ber_err_print( "*** end dump ***\n" );
+}
+
+#endif
+
+/* return the tag - LBER_DEFAULT returned means trouble
+ * assumes the tag is only one byte! */
+static ber_tag_t
+get_tag( Sockbuf *sb, BerElement *ber)
+{
+        unsigned char   xbyte;
+
+        if ( (BerRead( sb, (char *) &xbyte, 1 )) != 1 ) {
+                return( LBER_DEFAULT );
+        }
+
+        /* we only handle small (one byte) tags */
+        if ( (xbyte & LBER_BIG_TAG_MASK) == LBER_BIG_TAG_MASK ) {
+                return( LBER_DEFAULT );
+        }
+
+	ber->ber_tag_contents[0] = xbyte;
+	ber->ber_struct[BER_STRUCT_TAG].ldapiov_len = 1;
+	return((ber_tag_t)xbyte);
+}
+
+
+/* Error checking? */
+/* Takes a ber and returns the actual length */
+static ber_len_t
+get_ber_len( BerElement *ber)
+{
+  int noctets;
+  ber_len_t len = 0;
+  char xbyte;
+
+  xbyte = ber->ber_len_contents[0];
+  
+  /* long form */
+  if (xbyte & 0x80) {
+    noctets = (int) (xbyte & 0x7f);
+    if (noctets >= MAX_LEN_SIZE) {
+      return(LBER_DEFAULT);
+    }
+    SAFEMEMCPY((char*) &len + sizeof(ber_len_t) - noctets, &ber->ber_len_contents[1], noctets);
+    len = LBER_NTOHL(len);
+    return(len);
+  } else {
+    return((ber_len_t)(xbyte));
+  }
+}
+
+/* LBER_DEFAULT means trouble
+   reads in the length, stores it in ber->ber_struct, and returns get_ber_len */
+static ber_len_t
+read_len_in_ber( Sockbuf *sb, BerElement *ber)
+{
+  unsigned char xbyte;
+  int           noctets;
+  int           rc = 0, read_result = 0;
+
+  /*
+   * Next, read the length.  The first byte contains the length
+   * of the length.  If bit 8 is set, the length is the long
+   * form, otherwise it's the short form.  We don't allow a
+   * length that's greater than what we can hold in a ber_int_t
+   */
+  if ( ber->ber_tag_len_read == 1) {
+      /* the length of the length hasn't been read yet */
+      if ( BerRead( sb, (char *) &xbyte, 1 ) != 1 ) {
+	  return( LBER_DEFAULT );
+      }
+      ber->ber_tag_len_read = 2;
+      ber->ber_len_contents[0] = xbyte;
+  } else {
+      rc = ber->ber_tag_len_read - 2;
+      xbyte = ber->ber_len_contents[0];
+  }
+  
+  /* long form of the length value */
+  if ( xbyte & 0x80 ) {
+    noctets = (xbyte & 0x7f);
+    if ( noctets >= MAX_LEN_SIZE )
+	return( LBER_DEFAULT );
+    while (rc < noctets) {
+	read_result = BerRead( sb, &(ber->ber_len_contents[1]) + rc, noctets - rc );
+	if (read_result <= 0) {
+	    ber->ber_tag_len_read = rc + 2; /* so we can continue later - include tag and lenlen */
+	    return( LBER_DEFAULT );
+	}
+	rc += read_result;
+    }
+    ber->ber_tag_len_read = rc + 2; /* adds tag (1 byte) and lenlen (1 byte) */
+    ber->ber_struct[BER_STRUCT_LEN].ldapiov_len = 1 + noctets;
+  } else { /* short form of the length value */ 
+    ber->ber_struct[BER_STRUCT_LEN].ldapiov_len = 1;
+  }
+  return(get_ber_len(ber));
+}
+
+
+ber_tag_t
+LDAP_CALL
+ber_get_next( Sockbuf *sb, ber_len_t *len, BerElement *ber )
+{
+	ber_len_t	newlen;
+	ber_len_t	toread;
+	ber_int_t	rc;
+	ber_len_t   orig_taglen_read = 0;
+	char * orig_rwptr = ber->ber_rwptr ? ber->ber_rwptr : ber->ber_buf;
+
+#ifdef LDAP_DEBUG
+	if ( lber_debug )
+		ber_err_print( "ber_get_next\n" );
+#endif
+
+	/*
+	 * When rwptr is NULL this signifies that the tag and length have not been
+	 * read in their entirety yet. (if at all)
+	 */
+	if ( ber->ber_rwptr == NULL ) {
+
+            /* first save the amount we previously read, so we know what to return in len. */
+	    orig_taglen_read = ber->ber_tag_len_read;
+
+	    /* read the tag - if tag_len_read is greater than 0, then it has already been read. */
+	    if (ber->ber_tag_len_read == 0) {
+		if ((ber->ber_tag = get_tag(sb, ber)) == LBER_DEFAULT ) {
+		    *len = 0;
+		    return( LBER_DEFAULT );
+		}
+
+		ber->ber_tag_contents[0] = (char)ber->ber_tag; /* we only handle 1 byte tags */
+		ber->ber_tag_len_read = 1;  
+
+                /* check for validity */
+		if((sb->sb_options & LBER_SOCKBUF_OPT_VALID_TAG) &&
+		   (ber->ber_tag != sb->sb_valid_tag)) {
+		    *len = 1; /* we just read the tag so far */
+		    return( LBER_DEFAULT);
+		}              
+	    }	  
+	  
+	    /* read the length */
+	    if ((newlen = read_len_in_ber(sb, ber)) == LBER_DEFAULT ) {
+		*len = ber->ber_tag_len_read - orig_taglen_read;
+		return( LBER_DEFAULT );
+	    }
+
+	    /*
+	     * Finally, malloc a buffer for the contents and read it in.
+	     * It's this buffer that's passed to all the other ber decoding
+	     * routines.
+	     */
+	  
+#if defined( DOS ) && !( defined( _WIN32 ) || defined(XP_OS2) )
+	    if ( newlen > 65535 ) {	/* DOS can't allocate > 64K */
+		return( LBER_DEFAULT );
+	    }
+#endif /* DOS && !_WIN32 */
+	  
+	    if ( ( sb->sb_options & LBER_SOCKBUF_OPT_MAX_INCOMING_SIZE )
+		 && newlen > sb->sb_max_incoming ) {
+		return( LBER_DEFAULT );
+	    }
+	    
+	    /* check to see if we already have enough memory allocated */
+	    if ( ((ber_len_t) ber->ber_end - (ber_len_t) ber->ber_buf) < newlen) {
+			if ( ber->ber_buf && !(ber->ber_flags & LBER_FLAG_NO_FREE_BUFFER)) {
+				NSLBERI_FREE(ber->ber_buf);
+			}
+			if ( (ber->ber_buf = (char *)NSLBERI_CALLOC( 1,(size_t)newlen ))
+				 == NULL ) {
+				return( LBER_DEFAULT );
+			}
+			ber->ber_flags &= ~LBER_FLAG_NO_FREE_BUFFER;
+			orig_rwptr = ber->ber_buf;
+	    }
+	    
+	    
+	    ber->ber_len = newlen;
+	    ber->ber_ptr = ber->ber_buf;
+	    ber->ber_end = ber->ber_buf + newlen;
+	    ber->ber_rwptr = ber->ber_buf;
+	    ber->ber_tag_len_read = 0; /* now that rwptr is set, this doesn't matter */
+	}
+	
+	/* OK, we've malloc-ed the buffer; now read the rest of the expected length */
+	toread = (ber_len_t)ber->ber_end - (ber_len_t)ber->ber_rwptr;
+	do {
+	    if ( (rc = BerRead( sb, ber->ber_rwptr, (ber_int_t)toread )) <= 0 ) {
+		*len = (ber_len_t) ber->ber_rwptr - (ber_len_t) orig_rwptr;
+		return( LBER_DEFAULT );
+	    }
+	    
+	    toread -= rc;
+	    ber->ber_rwptr += rc;
+	} while ( toread > 0 );
+	
+#ifdef LDAP_DEBUG
+	if ( lber_debug ) {
+	    char msg[80];
+	    sprintf( msg, "ber_get_next: tag 0x%x len %d contents:\n",
+		     ber->ber_tag, ber->ber_len );
+	    ber_err_print( msg );
+	    if ( lber_debug > 1 )
+		ber_dump( ber, 1 );
+	}
+#endif
+	
+	*len = (ber_len_t) ber->ber_rwptr - (ber_len_t) orig_rwptr;
+	ber->ber_rwptr = NULL;
+	ber->ber_struct[BER_STRUCT_VAL].ldapiov_len = ber->ber_len;
+	return( ber->ber_tag );
+}
+
+Sockbuf *
+LDAP_CALL
+ber_sockbuf_alloc()
+{
+	return( (Sockbuf *)NSLBERI_CALLOC( 1, sizeof(struct sockbuf) ) );
+}
+
+void
+LDAP_CALL
+ber_sockbuf_free(Sockbuf *p)
+{
+	if ( p != NULL ) {
+		if ( p->sb_ber.ber_buf != NULL &&
+		    !(p->sb_ber.ber_flags & LBER_FLAG_NO_FREE_BUFFER) ) {
+			NSLBERI_FREE( p->sb_ber.ber_buf );
+		}
+		NSLBERI_FREE(p);
+	}
+}
+
+/*
+ * return 0 on success and -1 on error
+ */
+int
+LDAP_CALL
+ber_set_option( struct berelement *ber, int option, void *value )
+{
+  
+  /*
+   * memory allocation callbacks are global, so it is OK to pass
+   * NULL for ber.  Handle this as a special case.
+   */
+  if ( option == LBER_OPT_MEMALLOC_FN_PTRS ) {
+    /* struct copy */
+    nslberi_memalloc_fns = *((struct lber_memalloc_fns *)value);
+    return( 0 );
+  }
+  
+  /*
+   * lber_debug is global, so it is OK to pass
+   * NULL for ber.  Handle this as a special case.
+   */
+  if ( option == LBER_OPT_DEBUG_LEVEL ) {
+#ifdef LDAP_DEBUG
+    lber_debug = *(int *)value;
+#endif
+    return( 0 );
+  }
+
+ /*
+  * lber_bufsize is global, so it is OK to pass
+  * NULL for ber. Handle this as a special case.
+  */	
+  if ( option == LBER_OPT_BUFSIZE ) {
+	if ( *(size_t *)value > EXBUFSIZ ) {
+		lber_bufsize = *(size_t *)value;
+	}
+    return( 0 );
+  }
+
+  /*
+   * all the rest require a non-NULL ber
+   */
+  if ( !NSLBERI_VALID_BERELEMENT_POINTER( ber )) {
+    return( -1 );
+  }
+  
+  switch ( option ) {
+	case LBER_OPT_USE_DER:
+	case LBER_OPT_TRANSLATE_STRINGS:
+		if ( value != NULL ) {
+			ber->ber_options |= option;
+		} else {
+			ber->ber_options &= ~option;
+		}
+		break;
+	case LBER_OPT_REMAINING_BYTES:
+		ber->ber_end = ber->ber_ptr + *((ber_len_t *)value);
+		break;
+	case LBER_OPT_TOTAL_BYTES:
+		ber->ber_end = ber->ber_buf + *((ber_len_t *)value);
+		break;
+	case LBER_OPT_BYTES_TO_WRITE:
+		ber->ber_ptr = ber->ber_buf + *((ber_len_t *)value);
+		break;
+	default:
+		return( -1 );
+  }
+  
+  return( 0 );
+}
+
+/*
+ * return 0 on success and -1 on error
+ */
+int
+LDAP_CALL
+ber_get_option( struct berelement *ber, int option, void *value )
+{
+	/*
+	 * memory callocation callbacks are global, so it is OK to pass
+	 * NULL for ber.  Handle this as a special case
+	 */
+	if ( option == LBER_OPT_MEMALLOC_FN_PTRS ) {
+		/* struct copy */
+		*((struct lber_memalloc_fns *)value) = nslberi_memalloc_fns;
+		return( 0 );
+	}
+	
+	/*
+	 * lber_debug is global, so it is OK to pass
+	 * NULL for ber.  Handle this as a special case.
+	 */
+	if ( option == LBER_OPT_DEBUG_LEVEL ) {
+#ifdef LDAP_DEBUG
+	 *(int *)value =  lber_debug;
+#endif
+	  return( 0 );
+	}
+
+	/*
+	 * lber_bufsize is global, so it is OK to pass
+	 * NULL for ber. Handle this as a special case.
+	 */
+	if ( option == LBER_OPT_BUFSIZE ) {
+	  *(size_t *)value = lber_bufsize;
+	  return( 0 );
+	}
+
+	/*
+	 * all the rest require a non-NULL ber
+	 */
+	if ( !NSLBERI_VALID_BERELEMENT_POINTER( ber )) {
+		return( -1 );
+	}
+
+	switch ( option ) {
+	case LBER_OPT_USE_DER:
+	case LBER_OPT_TRANSLATE_STRINGS:
+		*((int *) value) = (ber->ber_options & option);
+		break;
+	case LBER_OPT_REMAINING_BYTES:
+		*((ber_len_t *) value) = ber->ber_end - ber->ber_ptr;
+		break;
+	case LBER_OPT_TOTAL_BYTES:
+		*((ber_len_t *) value) = ber->ber_end - ber->ber_buf;
+		break;
+	case LBER_OPT_BYTES_TO_WRITE:
+		*((ber_len_t *) value) = ber->ber_ptr - ber->ber_buf;
+		break;
+	default:
+		return( -1 );
+	}
+
+	return( 0 );
+}
+
+/*
+ * return 0 on success and -1 on error
+ */
+int
+LDAP_CALL
+ber_sockbuf_set_option( Sockbuf *sb, int option, void *value )
+{
+	struct lber_x_ext_io_fns	*extiofns;
+
+	if ( !NSLBERI_VALID_SOCKBUF_POINTER( sb )) {
+		return( -1 );
+	}
+
+        /* check for a NULL value for certain options. */
+	if (NULL == value) {
+	    switch ( option ) {
+	    case LBER_SOCKBUF_OPT_TO_FILE:
+	    case LBER_SOCKBUF_OPT_TO_FILE_ONLY:
+	    case LBER_SOCKBUF_OPT_NO_READ_AHEAD:
+	    case LBER_SOCKBUF_OPT_READ_FN:
+	    case LBER_SOCKBUF_OPT_WRITE_FN:
+	    case LBER_SOCKBUF_OPT_EXT_IO_FNS:
+	    case LBER_SOCKBUF_OPT_MAX_INCOMING_SIZE:
+		/* do nothing - it's OK to have a NULL value for these options */
+		break;
+	    default:
+		return( -1 );
+	    }
+	}
+
+	switch ( option ) {
+	case LBER_SOCKBUF_OPT_VALID_TAG:
+		sb->sb_valid_tag= *((ber_tag_t *) value);
+		/* use NULL to reset */
+		if ( value != NULL ) {
+			sb->sb_options |= option;
+		} else {
+			sb->sb_options &= ~option;
+		}
+		break;
+	case LBER_SOCKBUF_OPT_MAX_INCOMING_SIZE:
+		if ( value != NULL ) {
+		    sb->sb_max_incoming = *((ber_len_t *) value);
+		    sb->sb_options |= option;
+		} else {
+		    /* setting the max incoming to 0 seems to be the only
+		       way to tell the callers of ber_sockbuf_get_option
+		       that this option isn't set. */
+		    sb->sb_max_incoming = 0;
+		    sb->sb_options &= ~option;
+		}
+		break;
+	case LBER_SOCKBUF_OPT_TO_FILE:
+	case LBER_SOCKBUF_OPT_TO_FILE_ONLY:
+	case LBER_SOCKBUF_OPT_NO_READ_AHEAD:
+		if ( value != NULL ) {
+			sb->sb_options |= option;
+		} else {
+			sb->sb_options &= ~option;
+		}
+		break;
+	case LBER_SOCKBUF_OPT_DESC:
+		sb->sb_sd = *((LBER_SOCKET *) value);
+		break;
+	case LBER_SOCKBUF_OPT_COPYDESC:
+		sb->sb_copyfd = *((LBER_SOCKET *) value);
+		break;
+	case LBER_SOCKBUF_OPT_READ_FN:
+		sb->sb_io_fns.lbiof_read = (LDAP_IOF_READ_CALLBACK *) value;
+		nslberi_install_compat_io_fns( sb );
+		break;
+	case LBER_SOCKBUF_OPT_WRITE_FN:
+		sb->sb_io_fns.lbiof_write = (LDAP_IOF_WRITE_CALLBACK *) value;
+		nslberi_install_compat_io_fns( sb );
+		break;
+	case LBER_SOCKBUF_OPT_EXT_IO_FNS:
+		extiofns = (struct lber_x_ext_io_fns *) value;
+		if ( extiofns == NULL ) {	/* remove */
+			(void)memset( (char *)&sb->sb_ext_io_fns, '\0',
+				sizeof(sb->sb_ext_io_fns ));
+		} else if ( extiofns->lbextiofn_size
+		    == LBER_X_EXTIO_FNS_SIZE ) {
+			/* struct copy */
+			sb->sb_ext_io_fns = *extiofns;
+		} else if ( extiofns->lbextiofn_size
+			    == LBER_X_EXTIO_FNS_SIZE_REV0 ) {
+			/* backwards compatiblity for older struct */
+			sb->sb_ext_io_fns.lbextiofn_size =
+				LBER_X_EXTIO_FNS_SIZE;
+			sb->sb_ext_io_fns.lbextiofn_read =
+				extiofns->lbextiofn_read;
+			sb->sb_ext_io_fns.lbextiofn_write =
+				    extiofns->lbextiofn_write;
+			sb->sb_ext_io_fns.lbextiofn_writev = NULL;
+			sb->sb_ext_io_fns.lbextiofn_socket_arg =
+				    extiofns->lbextiofn_socket_arg;
+		} else {
+			return( -1 );
+		}
+		break;
+	case LBER_SOCKBUF_OPT_SOCK_ARG:
+		sb->sb_ext_io_fns.lbextiofn_socket_arg = 
+		(struct lextiof_socket_private *) value;
+		break;
+	default:
+		return( -1 );
+	}
+
+	return( 0 );
+}
+
+/*
+ * return 0 on success and -1 on error
+ */
+int
+LDAP_CALL
+ber_sockbuf_get_option( Sockbuf *sb, int option, void *value )
+{
+	struct lber_x_ext_io_fns	*extiofns;
+
+	if ( !NSLBERI_VALID_SOCKBUF_POINTER( sb ) || (NULL == value)) {
+		return( -1 );
+	}
+
+	switch ( option ) {
+	case LBER_SOCKBUF_OPT_VALID_TAG:
+		*((ber_tag_t *) value) = sb->sb_valid_tag;
+		break;
+	case LBER_SOCKBUF_OPT_MAX_INCOMING_SIZE:
+		*((ber_len_t *) value) = sb->sb_max_incoming;
+		break;
+	case LBER_SOCKBUF_OPT_TO_FILE:
+	case LBER_SOCKBUF_OPT_TO_FILE_ONLY:
+	case LBER_SOCKBUF_OPT_NO_READ_AHEAD:
+		*((int *) value) = (sb->sb_options & option);
+		break;
+	case LBER_SOCKBUF_OPT_DESC:
+		*((LBER_SOCKET *) value) = sb->sb_sd;
+		break;
+	case LBER_SOCKBUF_OPT_COPYDESC:
+		*((LBER_SOCKET *) value) = sb->sb_copyfd;
+		break;
+	case LBER_SOCKBUF_OPT_READ_FN:
+		*((LDAP_IOF_READ_CALLBACK **) value)
+		    = sb->sb_io_fns.lbiof_read;
+		break;
+	case LBER_SOCKBUF_OPT_WRITE_FN:
+		*((LDAP_IOF_WRITE_CALLBACK **) value)
+		    = sb->sb_io_fns.lbiof_write;
+		break;
+	case LBER_SOCKBUF_OPT_EXT_IO_FNS:
+		extiofns = (struct lber_x_ext_io_fns *) value;
+        if ( extiofns == NULL ) {
+			return( -1 );
+		} else if ( extiofns->lbextiofn_size
+			    == LBER_X_EXTIO_FNS_SIZE ) {
+			/* struct copy */
+			*extiofns = sb->sb_ext_io_fns;
+		} else if ( extiofns->lbextiofn_size
+			    == LBER_X_EXTIO_FNS_SIZE_REV0 ) {
+			/* backwards compatiblity for older struct */
+			extiofns->lbextiofn_read = sb->sb_ext_io_fns.lbextiofn_read;
+			extiofns->lbextiofn_write = sb->sb_ext_io_fns.lbextiofn_write;
+			extiofns->lbextiofn_socket_arg = sb->sb_ext_io_fns.lbextiofn_socket_arg;
+		} else {
+			return( -1 );
+		}
+		break;
+	case LBER_SOCKBUF_OPT_SOCK_ARG:
+		*((struct lextiof_socket_private **)value) = sb->sb_ext_io_fns.lbextiofn_socket_arg;
+		break;
+	default:
+		return( -1 );
+	}
+
+	return( 0 );
+}
+
+
+/* new dboreham code below: */
+
+struct byte_buffer  {
+	unsigned char *p;
+	int offset;
+	int length;
+};
+typedef struct byte_buffer byte_buffer;
+
+
+/* This call allocates us a BerElement structure plus some extra memory. 
+ * It returns a pointer to the BerElement, plus a pointer to the extra memory.
+ * This routine also allocates a ber data buffer within the same block, thus
+ * saving a call to calloc later when we read data.
+ */
+void*
+LDAP_CALL
+ber_special_alloc(size_t size, BerElement **ppBer)
+{
+	char *mem = NULL;
+
+	/* Make sure mem size requested is aligned */
+	if (0 != ( size & 0x03 )) {
+		size += (sizeof(ber_int_t) - (size & 0x03));
+	}
+
+	mem = NSLBERI_MALLOC(sizeof(struct berelement) + lber_bufsize + size );
+	if (NULL == mem) {
+		return NULL;
+	} 
+	*ppBer = (BerElement*) (mem + size);
+	memset(*ppBer,0,sizeof(struct berelement));
+	(*ppBer)->ber_tag = LBER_DEFAULT;
+	(*ppBer)->ber_buf = mem + size + sizeof(struct berelement);
+	(*ppBer)->ber_ptr = (*ppBer)->ber_buf;
+	(*ppBer)->ber_end = (*ppBer)->ber_buf + lber_bufsize;
+	(*ppBer)->ber_flags = LBER_FLAG_NO_FREE_BUFFER;
+	return (void*)mem;
+}
+
+void
+LDAP_CALL
+ber_special_free(void* buf, BerElement *ber)
+{
+	if (!(ber->ber_flags & LBER_FLAG_NO_FREE_BUFFER)) {
+		NSLBERI_FREE(ber->ber_buf);
+	}
+	NSLBERI_FREE( buf );
+}
+
+/* Copy up to bytes_to_read bytes from b into return_buffer.
+ * Returns a count of bytes copied (always >= 0).
+ */
+static int
+read_bytes(byte_buffer *b, unsigned char *return_buffer, int bytes_to_read)
+{
+	/* copy up to bytes_to_read bytes into the caller's buffer, return the number of bytes copied */
+	int bytes_to_copy = 0;
+
+	if (bytes_to_read <= (b->length - b->offset) ) {
+		bytes_to_copy = bytes_to_read;
+	} else {
+		bytes_to_copy = (b->length - b->offset);
+	}
+	if (1 == bytes_to_copy) {
+		*return_buffer = *(b->p+b->offset++);
+	} else if (bytes_to_copy <= 0) {
+		bytes_to_copy = 0;	/* never return a negative result */
+	} else {
+		SAFEMEMCPY(return_buffer,b->p+b->offset,bytes_to_copy);
+		b->offset += bytes_to_copy;
+	}
+	return bytes_to_copy;
+}
+
+/* return the tag - LBER_DEFAULT returned means trouble */
+static ber_tag_t
+get_buffer_tag(byte_buffer *sb )
+{
+	unsigned char	xbyte;
+	ber_tag_t		tag;
+	char			*tagp;
+	int				i;
+
+	if ( (i = read_bytes( sb, &xbyte, 1 )) != 1 ) {
+		return( LBER_DEFAULT );
+	}
+
+	if ( (xbyte & LBER_BIG_TAG_MASK) != LBER_BIG_TAG_MASK ) {
+		return( (ber_uint_t) xbyte );
+	}
+
+	tagp = (char *) &tag;
+	tagp[0] = xbyte;
+	for ( i = 1; i < sizeof(ber_int_t); i++ ) {
+		if ( read_bytes( sb, &xbyte, 1 ) != 1 )
+			return( LBER_DEFAULT );
+
+		tagp[i] = xbyte;
+
+		if ( ! (xbyte & LBER_MORE_TAG_MASK) )
+			break;
+	}
+
+	/* tag too big! */
+	if ( i == sizeof(ber_int_t) )
+		return( LBER_DEFAULT );
+
+	/* want leading, not trailing 0's */
+	return( tag >> (sizeof(ber_int_t) - i - 1) );
+}
+
+/* Like ber_get_next, but from a byte buffer the caller already has. */
+/* Bytes_Scanned returns the number of bytes we actually looked at in the buffer. */
+/* ber_get_next_buffer is now implemented in terms of ber_get_next_buffer_ext */
+/* and is here for backward compatibility.  This new function allows us to pass */
+/* the Sockbuf structure along */
+
+ber_uint_t
+LDAP_CALL
+ber_get_next_buffer( void *buffer, size_t buffer_size, ber_len_t *len,
+    BerElement *ber, ber_uint_t *Bytes_Scanned )
+{
+	return (ber_get_next_buffer_ext( buffer, buffer_size, len, ber,
+		Bytes_Scanned, NULL));
+}
+
+/*
+ * Returns the tag of the message or LBER_ return code if an error occurs.
+ *
+ * If there was not enough data in the buffer to complete the message this
+ * is a "soft" error. In this case, *Bytes_Scanned is set to a positive
+ * number and return code is set to LBER_DEFAULT.
+ *
+ * On overflow condition when the length is either bigger than ber_uint_t 
+ * type or the value preset via LBER_SOCKBUF_OPT_MAX_INCOMING_SIZE option,
+ * *Bytes_Scanned is set to zero and return code is set to LBER_OVERFLOW.
+ *
+ * For backward compatibility errno is also set on these error conditions:
+ *
+ * EINVAL   - LBER_SOCKBUF_OPT_VALID_TAG option set but tag doesnt match.
+ * EMSGSIZE - an overflow condition as described above for LBER_OVERFLOW.
+ */
+ber_uint_t
+LDAP_CALL
+ber_get_next_buffer_ext( void *buffer, size_t buffer_size, ber_len_t *len,
+    BerElement *ber, ber_uint_t *Bytes_Scanned, Sockbuf *sock )
+{
+	ber_tag_t		tag = 0; 
+	ber_len_t		netlen;
+	ber_len_t		toread;
+	unsigned char	lc;
+	ssize_t			rc;
+	int				noctets, diff;
+	byte_buffer		sb = {0};
+
+
+	/*
+	 * Any ber element looks like this: tag length contents.
+	 * Assuming everything's ok, we return the tag byte (we
+	 * can assume a single byte), return the length in len,
+	 * and the rest of the undecoded element in buf.
+	 *
+	 * Assumptions:
+	 *	1) small tags (less than 128)
+	 *	2) definite lengths
+	 *	3) primitive encodings used whenever possible
+	 */
+
+	/*
+	 * first time through - malloc the buffer, set up ptrs, and
+	 * read the tag and the length and as much of the rest as we can
+	 */
+
+	sb.p = buffer;
+	sb.length = buffer_size;
+
+	if ( ber->ber_rwptr == NULL ) {
+
+		/*
+		 * First, we read the tag.
+		 */
+
+        /* if we have been called before with a fragment not
+         * containing a complete length, we have no rwptr but
+         * a tag already
+         */
+		if ( ber->ber_tag == LBER_DEFAULT ) {
+			if ( (tag = get_buffer_tag( &sb )) == LBER_DEFAULT ) {
+				goto premature_exit;
+			}
+			ber->ber_tag = tag;
+		}
+		
+		if((sock->sb_options & LBER_SOCKBUF_OPT_VALID_TAG) &&
+		   (ber->ber_tag != sock->sb_valid_tag)) {
+#if !defined( macintosh ) && !defined( DOS )
+			errno = EINVAL;
+#endif
+            goto error_exit;
+		}
+
+		/* If we have been called before with an incomplete length,
+		 * the fragment of the length read is in ber->ber_len_contents
+		 * ber->ber_tag_len_read is the # of bytes of the length available
+		 * from a previous fragment
+		 */
+
+		if (ber->ber_tag_len_read) {
+			int nbytes;
+			
+			noctets = ((ber->ber_len_contents[0]) & 0x7f);
+			diff = noctets + 1 /* tag */ - ber->ber_tag_len_read;
+			
+			if ( (nbytes = read_bytes( &sb, (unsigned char *) &ber->ber_len_contents[0] +
+						   ber->ber_tag_len_read, diff )) != diff ) {
+				
+				if (nbytes > 0)
+					ber->ber_tag_len_read+=nbytes;
+				
+				goto premature_exit;
+			}
+			*len = get_ber_len(ber); /* cast ber->ber_len_contents to unsigned long */
+			
+		} else {
+			/*
+			 * Next, read the length.  The first byte contains the length
+			 * of the length.  If bit 8 is set, the length is the long
+			 * form, otherwise it's the short form.  We don't allow a
+			 * length that's greater than what we can hold in an unsigned
+			 * long.
+			 */
+
+			*len = netlen = 0;
+			if ( read_bytes( &sb, &lc, 1 ) != 1 ) {
+				goto premature_exit;
+			}
+			if ( lc & 0x80 ) {
+				int nbytes;
+				
+				noctets = (lc & 0x7f);
+				if ( noctets > sizeof(ber_uint_t) ) {
+#if !defined( macintosh ) && !defined( DOS )
+                    errno = EMSGSIZE;
+#endif
+                    *Bytes_Scanned = 0;
+                    return(LBER_OVERFLOW);
+                }
+                diff = sizeof(ber_uint_t) - noctets;
+				if ( (nbytes = read_bytes( &sb, (unsigned char *)&netlen + diff,
+							   noctets )) != noctets ) {				       
+					/*
+					 * The length is in long form and we don't get it in one
+					 * fragment, so stash partial length in the ber element
+					 * for later use
+					 */
+
+					ber->ber_tag_len_read = nbytes + 1;
+					ber->ber_len_contents[0]=lc;					
+					memset(&(ber->ber_len_contents[1]), 0, sizeof(ber_uint_t));
+					SAFEMEMCPY(&(ber->ber_len_contents[1]), (unsigned char *)&netlen + diff, nbytes);
+
+					goto premature_exit;
+                }
+                    *len = LBER_NTOHL( netlen );
+                } else {
+                    *len = lc;
+                }
+		}
+		
+        ber->ber_len = *len;
+		/* length fully decoded */
+		ber->ber_tag_len_read=0;
+		/*
+		 * Finally, malloc a buffer for the contents and read it in.
+		 * It's this buffer that's passed to all the other ber decoding
+		 * routines.
+		 */
+
+#if defined( DOS ) && !defined( _WIN32 )
+		if ( *len > 65535 ) {	/* DOS can't allocate > 64K */
+			goto premature_exit;
+		}
+#endif /* DOS && !_WIN32 */
+
+        if ( (sock != NULL)  &&
+		    ( sock->sb_options & LBER_SOCKBUF_OPT_MAX_INCOMING_SIZE )
+                    && (*len > sock->sb_max_incoming) ) {
+#if !defined( macintosh ) && !defined( DOS )
+                    errno = EMSGSIZE;
+#endif
+                    *Bytes_Scanned = 0;
+                    return( LBER_OVERFLOW );
+        }
+
+		if ( ber->ber_buf + *len > ber->ber_end ) {
+			if ( nslberi_ber_realloc( ber, *len ) != 0 )
+				goto error_exit;
+		}
+		ber->ber_ptr = ber->ber_buf;
+		ber->ber_end = ber->ber_buf + *len;
+		ber->ber_rwptr = ber->ber_buf;
+	}
+
+	toread = (ber_len_t)ber->ber_end - (ber_len_t)ber->ber_rwptr;
+	do {
+		if ( (rc = read_bytes( &sb, (unsigned char *)ber->ber_rwptr,
+		    (ber_int_t)toread )) <= 0 ) {
+			goto premature_exit;
+		}
+
+		toread -= rc;
+		ber->ber_rwptr += rc;
+	} while ( toread > 0 );
+
+	*len = ber->ber_len;
+	*Bytes_Scanned = sb.offset;
+	return( ber->ber_tag );
+
+premature_exit:
+	/*
+	 * we're here because we hit the end of the buffer before seeing
+	 * all of the PDU
+	 */
+	*Bytes_Scanned = sb.offset;
+	return(LBER_DEFAULT);
+
+error_exit:
+	*Bytes_Scanned = 0;
+	return(LBER_DEFAULT);
+}
+
+
+/* The ber_flatten routine allocates a struct berval whose contents
+ * are a BER encoding taken from the ber argument. The bvPtr pointer
+ * points to the returned berval, which must be freed using
+ * ber_bvfree().  This routine returns 0 on success and -1 on error.
+ * The use of ber_flatten on a BerElement in which all '{' and '}'
+ * format modifiers have not been properly matched can result in a
+ * berval whose contents are not a valid BER encoding. 
+ * Note that the ber_ptr is not modified.
+ */
+int
+LDAP_CALL
+ber_flatten( BerElement *ber, struct berval **bvPtr )
+{
+	struct berval *new;
+	ber_len_t len;
+
+	/* allocate a struct berval */
+	if ( (new = (struct berval *)NSLBERI_MALLOC( sizeof(struct berval) ))
+	    == NULL ) {
+		return( -1 );
+	}
+
+	/*
+	 * Copy everything from the BerElement's ber_buf to ber_ptr
+	 * into the berval structure.
+	 */
+	if ( ber == NULL ) {
+	    new->bv_val = NULL;
+	    new->bv_len = 0;
+	} else {
+ 	    len = ber->ber_ptr - ber->ber_buf; 
+	    if ( ( new->bv_val = (char *)NSLBERI_MALLOC( len + 1 )) == NULL ) {
+		    ber_bvfree( new );
+		    return( -1 );
+	    }
+ 	    SAFEMEMCPY( new->bv_val, ber->ber_buf, (size_t)len ); 
+	    new->bv_val[len] = '\0';
+	    new->bv_len = len;
+	}
+
+	/* set bvPtr pointer to point to the returned berval */
+  	*bvPtr = new; 
+
+        return( 0 );
+}
+
+
+/*
+ * The ber_init function constructs and returns a new BerElement
+ * containing a copy of the data in the bv argument.  ber_init
+ * returns the null pointer on error.
+ */
+BerElement *
+LDAP_CALL
+ber_init( const struct berval *bv )
+{
+	BerElement *ber;
+
+	/* construct BerElement */
+	if (( ber = ber_alloc_t( 0 )) != NULLBER ) {
+		/* copy data from the bv argument into BerElement */
+		/* XXXmcs: had to cast unsigned long bv_len to long */
+		if ( (ber_write ( ber, bv->bv_val, bv->bv_len, 0 ))
+		    != (ber_slen_t)bv->bv_len ) {
+			ber_free( ber, 1 );
+			return( NULL );
+		}
+	}
+	
+	/*
+	 * reset ber_ptr back to the beginning of buffer so that this new
+	 * and initialized ber element can be READ
+	 */
+	ber_reset( ber, 1);
+
+	/*
+	 * return a ptr to a new BerElement containing a copy of the data
+	 * in the bv argument or a null pointer on error
+	 */
+	return( ber );
+}
+
+
+/*
+ * memory allocation functions.
+ */
+void *
+nslberi_malloc( size_t size )
+{
+	return( nslberi_memalloc_fns.lbermem_malloc == NULL ?
+	    malloc( size ) :
+	    nslberi_memalloc_fns.lbermem_malloc( size ));
+}
+
+
+void *
+nslberi_calloc( size_t nelem, size_t elsize )
+{
+	return( nslberi_memalloc_fns.lbermem_calloc == NULL ?
+	    calloc(  nelem, elsize ) :
+	    nslberi_memalloc_fns.lbermem_calloc( nelem, elsize ));
+}
+
+
+void *
+nslberi_realloc( void *ptr, size_t size )
+{
+	return( nslberi_memalloc_fns.lbermem_realloc == NULL ?
+	    realloc( ptr, size ) :
+	    nslberi_memalloc_fns.lbermem_realloc( ptr, size ));
+}
+
+
+void
+nslberi_free( void *ptr )
+{
+	if ( nslberi_memalloc_fns.lbermem_free == NULL ) {
+		free( ptr );
+	} else {
+		nslberi_memalloc_fns.lbermem_free( ptr );
+	}
+}
+
+
+/*
+ ******************************************************************************
+ * functions to bridge the gap between new extended I/O functions that are
+ *    installed using ber_sockbuf_set_option( ..., LBER_SOCKBUF_OPT_EXT_IO_FNS,
+ *    ... ).
+ *
+ * the basic strategy is to use the new extended arg to hold a pointer to the
+ *    Sockbuf itself so we can find the old functions and call them.
+ * note that the integer socket s passed in is not used.  we use the sb_sd
+ *    from the Sockbuf itself because it is the correct type.
+ */
+static int
+nslberi_extread_compat( int s, void *buf, int len,
+	struct lextiof_socket_private *arg )
+{
+	Sockbuf	*sb = (Sockbuf *)arg;
+
+	return( sb->sb_io_fns.lbiof_read( sb->sb_sd, buf, len ));
+}
+
+
+static int
+nslberi_extwrite_compat( int s, const void *buf, int len,
+	struct lextiof_socket_private *arg )
+{
+	Sockbuf	*sb = (Sockbuf *)arg;
+
+	return( sb->sb_io_fns.lbiof_write( sb->sb_sd, buf, len ));
+}
+
+
+/*
+ * Install I/O compatiblity functions.  This can't fail.
+ */
+static void
+nslberi_install_compat_io_fns( Sockbuf *sb )
+{
+	sb->sb_ext_io_fns.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE;
+	sb->sb_ext_io_fns.lbextiofn_read = nslberi_extread_compat;
+	sb->sb_ext_io_fns.lbextiofn_write = nslberi_extwrite_compat;
+	sb->sb_ext_io_fns.lbextiofn_writev = NULL;
+	sb->sb_ext_io_fns.lbextiofn_socket_arg = (void *)sb;
+}
+/*
+ * end of compat I/O functions
+ ******************************************************************************
+ */
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/liblber/lber-int.h
@@ -0,0 +1,305 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+/* lbet-int.h - internal header file for liblber */
+
+#ifndef _LBERINT_H
+#define _LBERINT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#ifdef macintosh
+# include "ldap-macos.h"
+#else /* macintosh */
+#if !defined(BSDI) && !defined(DARWIN) && !defined(FREEBSD) && !defined(OPENBSD)
+# include <malloc.h>
+#endif
+# include <errno.h>
+# include <sys/types.h>
+#if defined(SUNOS4) || defined(SCOOS)
+# include <sys/time.h>
+#endif
+#if defined( _WINDOWS )
+#  define WIN32_LEAN_AND_MEAN
+#  include <windows.h>
+#  include <basetsd.h>
+#  define ssize_t SSIZE_T
+#  include <time.h>
+/* No stderr in a 16-bit Windows DLL */
+#  if defined(_WINDLL) && !defined(_WIN32)
+#    define USE_DBG_WIN
+#  endif
+# else
+/* #  include <sys/varargs.h> */
+#  include <sys/socket.h>
+#  include <netinet/in.h>
+#if !defined(XP_OS2) && !defined(DARWIN)
+#  include <unistd.h>
+#endif
+# endif /* defined( _WINDOWS ) */
+#endif /* macintosh */
+
+#include <memory.h>
+#include <string.h>
+#include "portable.h"
+
+#ifdef _WINDOWS
+#  if defined(FD_SETSIZE)
+#  else
+#    define FD_SETSIZE 256 /* set it before winsock sets it to 64! */
+#  endif
+#include <winsock.h>
+#include <io.h>
+#endif /* _WINDOWS */
+
+#ifdef XP_OS2
+#include <io.h>
+#endif /* XP_OS2 */
+
+/* No stderr in a 16-bit Windows DLL */
+#if defined(_WINDLL) && !defined(_WIN32)
+#define stderr NULL
+#endif
+
+#include "lber.h"
+
+#ifdef macintosh
+#define NSLDAPI_LBER_SOCKET_IS_PTR
+#endif
+
+#define OLD_LBER_SEQUENCE	0x10	/* w/o constructed bit - broken */
+#define OLD_LBER_SET		0x11	/* w/o constructed bit - broken */
+
+#ifndef _IFP
+#define _IFP
+typedef int (LDAP_C LDAP_CALLBACK *IFP)();
+#endif
+
+typedef struct seqorset {
+  ber_len_t	sos_clen;
+  ber_tag_t	sos_tag;
+  char		*sos_first;
+  char		*sos_ptr;
+  struct seqorset	*sos_next;
+} Seqorset;
+#define NULLSEQORSET	((Seqorset *) 0)
+
+#define SOS_STACK_SIZE 8 /* depth of the pre-allocated sos structure stack */
+
+#define MAX_TAG_SIZE (1 + sizeof(ber_int_t)) /* One byte for the length of the tag */
+#define MAX_LEN_SIZE (1 + sizeof(ber_int_t)) /* One byte for the length of the length */
+#define MAX_VALUE_PREFIX_SIZE (2 + sizeof(ber_int_t)) /* 1 byte for the tag and 1 for the len (msgid) */
+#define BER_ARRAY_QUANTITY 7 /* 0:Tag   1:Length   2:Value-prefix   3:Value   4:Value-suffix  */
+#define BER_STRUCT_TAG 0     /* 5:ControlA   6:ControlB */
+#define BER_STRUCT_LEN 1
+#define BER_STRUCT_PRE 2
+#define BER_STRUCT_VAL 3
+#define BER_STRUCT_SUF 4
+#define BER_STRUCT_CO1 5
+#define BER_STRUCT_CO2 6
+
+struct berelement {
+  ldap_x_iovec  ber_struct[BER_ARRAY_QUANTITY];   /* See above */
+
+  char          ber_tag_contents[MAX_TAG_SIZE];
+  char          ber_len_contents[MAX_LEN_SIZE];
+  char          ber_pre_contents[MAX_VALUE_PREFIX_SIZE];
+  char          ber_suf_contents[MAX_LEN_SIZE+1];
+
+  char      *ber_buf; /* update the value value when writing in case realloc is called */
+  char		*ber_ptr;
+  char		*ber_end;
+  struct seqorset	*ber_sos;
+  ber_len_t ber_tag_len_read;
+  ber_tag_t	ber_tag; /* Remove me someday */
+  ber_len_t	ber_len; /* Remove me someday */
+  int		ber_usertag;
+  char		ber_options;
+  char		*ber_rwptr;
+  BERTranslateProc ber_encode_translate_proc;
+  BERTranslateProc ber_decode_translate_proc;
+  int		ber_flags;
+#define LBER_FLAG_NO_FREE_BUFFER	1	/* don't free ber_buf */
+  unsigned  int ber_buf_reallocs;		/* realloc counter */
+  int		ber_sos_stack_posn;
+  Seqorset	ber_sos_stack[SOS_STACK_SIZE];
+};
+
+#define BER_CONTENTS_STRUCT_SIZE (sizeof(ldap_x_iovec) * BER_ARRAY_QUANTITY)
+
+#define NULLBER	((BerElement *)NULL)
+
+#ifdef LDAP_DEBUG
+void ber_dump( BerElement *ber, int inout );
+#endif
+
+
+
+/*
+ * structure for read/write I/O callback functions.
+ */
+struct nslberi_io_fns {
+    LDAP_IOF_READ_CALLBACK	*lbiof_read;
+    LDAP_IOF_WRITE_CALLBACK	*lbiof_write;
+};
+
+
+/*
+ * Old  structure for use with LBER_SOCKBUF_OPT_EXT_IO_FNS:
+ */
+struct lber_x_ext_io_fns_rev0 {
+	    /* lbextiofn_size should always be set to LBER_X_EXTIO_FNS_SIZE */
+	int				lbextiofn_size;
+	LDAP_X_EXTIOF_READ_CALLBACK	*lbextiofn_read;
+	LDAP_X_EXTIOF_WRITE_CALLBACK	*lbextiofn_write;
+	struct lextiof_socket_private	*lbextiofn_socket_arg;
+};
+#define LBER_X_EXTIO_FNS_SIZE_REV0    sizeof(struct lber_x_ext_io_fns_rev0)
+
+
+
+struct sockbuf {
+	LBER_SOCKET	sb_sd;
+	BerElement	sb_ber;
+	int		sb_naddr;	/* > 0 implies using CLDAP (UDP) */
+	void		*sb_useaddr;	/* pointer to sockaddr to use next */
+	void		*sb_fromaddr;	/* pointer to message source sockaddr */
+	void		**sb_addrs;	/* actually an array of pointers to
+					   sockaddrs */
+
+	int		sb_options;	/* to support copying ber elements */
+	LBER_SOCKET	sb_copyfd;	/* for LBER_SOCKBUF_OPT_TO_FILE* opts */
+	ber_len_t	sb_max_incoming;
+	ber_tag_t   sb_valid_tag;	/* valid tag to accept */
+	struct nslberi_io_fns
+			sb_io_fns;	/* classic I/O callback functions */
+
+	struct lber_x_ext_io_fns
+			sb_ext_io_fns;	/* extended I/O callback functions */
+};
+#define NULLSOCKBUF	((Sockbuf *)NULL)
+
+/* needed by libldap, even in non-DEBUG builds */
+void ber_err_print( char *data );
+
+#ifndef NSLBERI_LBER_INT_FRIEND
+/*
+ * Everything from this point on is excluded if NSLBERI_LBER_INT_FRIEND is
+ * defined.  The code under ../libraries/libldap defines this.
+ */
+
+#define READBUFSIZ	8192
+
+/*
+ * macros used to check validity of data structures and parameters
+ */
+#define NSLBERI_VALID_BERELEMENT_POINTER( ber ) \
+	( (ber) != NULLBER )
+
+#define NSLBERI_VALID_SOCKBUF_POINTER( sb ) \
+	( (sb) != NULLSOCKBUF )
+
+#define LBER_HTONL( l )	htonl( l )
+#define LBER_NTOHL( l )	ntohl( l )
+
+/* function prototypes */
+#ifdef LDAP_DEBUG
+void lber_bprint( char *data, int len );
+#endif
+void ber_err_print( char *data );
+void *nslberi_malloc( size_t size );
+void *nslberi_calloc( size_t nelem, size_t elsize );
+void *nslberi_realloc( void *ptr, size_t size );
+void nslberi_free( void *ptr );
+int nslberi_ber_realloc( BerElement *ber, ber_len_t len );
+
+/* blame: dboreham 
+ * slapd spends much of its time doing memcpy's for the ber code.
+ * Most of these are single-byte, so we special-case those and speed
+ * things up considerably. 
+ */
+
+#ifdef sunos4
+#define THEMEMCPY( d, s, n )	bcopy( s, d, n )
+#else /* sunos4 */
+#define THEMEMCPY( d, s, n )	memmove( d, s, n )
+#endif /* sunos4 */
+
+#ifdef SAFEMEMCPY
+#undef SAFEMEMCPY
+#define SAFEMEMCPY(d,s,n) if (1 == n) *((char*)d) = *((char*)s); else THEMEMCPY(d,s,n);
+#endif
+
+/*
+ * Memory allocation done in liblber should all go through one of the
+ * following macros. This is so we can plug-in alternative memory
+ * allocators, etc. as the need arises.
+ */
+#define NSLBERI_MALLOC( size )		nslberi_malloc( size )
+#define NSLBERI_CALLOC( nelem, elsize )	nslberi_calloc( nelem, elsize )
+#define NSLBERI_REALLOC( ptr, size )	nslberi_realloc( ptr, size )
+#define NSLBERI_FREE( ptr )		nslberi_free( ptr )
+
+/* allow the library to access the debug variable */
+
+extern int lber_debug;
+
+#endif /* !NSLBERI_LBER_INT_FRIEND */
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _LBERINT_H */
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/Makefile.in
@@ -0,0 +1,375 @@
+# 
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+# 
+# The contents of this file are subject to the Mozilla Public License Version 
+# 1.1 (the "License"); you may not use this file except in compliance with 
+# the License. You may obtain a copy of the License at 
+# http://www.mozilla.org/MPL/
+# 
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+# 
+# The Original Code is Mozilla Communicator client code, released
+# March 31, 1998.
+# 
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 1998-1999
+# the Initial Developer. All Rights Reserved.
+# 
+# Contributor(s):
+# 
+# Alternatively, the contents of this file may be used under the terms of
+# either of the GNU General Public License Version 2 or later (the "GPL"),
+# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+# 
+# ***** END LICENSE BLOCK ***** 
+
+MOD_DEPTH 	= ../../..
+srcdir		= @srcdir@
+topsrcdir	= @top_srcdir@
+SASL_CFLAGS     = @SASL_CFLAGS@
+SASL_LIBS       = @SASL_LIBS@
+HAVE_SASL	= @HAVE_SASL@
+
+include $(MOD_DEPTH)/config/autoconf.mk
+include $(topsrcdir)/build.mk
+
+SRCS		= abandon.c \
+		  add.c \
+		  authzidctrl.c \
+		  bind.c \
+		  cache.c \
+		  charray.c \
+		  charset.c \
+		  compare.c \
+		  compat.c \
+		  control.c \
+		  countvalues.c \
+		  delete.c \
+		  disptmpl.c \
+		  dsparse.c \
+		  error.c \
+		  extendop.c \
+		  free.c \
+		  freevalues.c \
+		  friendly.c \
+		  getattr.c \
+		  getdn.c \
+		  getdxbyname.c \
+		  geteffectiverightsctrl.c \
+		  getentry.c \
+		  getfilter.c \
+		  getoption.c \
+		  getvalues.c \
+		  memcache.c \
+		  message.c \
+		  modify.c \
+		  open.c \
+		  os-ip.c \
+		  proxyauthctrl.c \
+		  psearch.c \
+		  pwmodext.c \
+		  pwpctrl.c \
+		  referral.c \
+		  regex.c \
+		  rename.c \
+		  request.c \
+		  reslist.c \
+		  result.c \
+		  saslbind.c \
+		  sbind.c \
+		  search.c \
+		  setoption.c \
+		  sort.c \
+		  sortctrl.c \
+		  srchpref.c \
+		  tmplout.c \
+		  ufn.c \
+		  unbind.c \
+		  unescape.c \
+		  url.c \
+		  userstatusctrl.c \
+		  utf8.c \
+		  vlistctrl.c \
+		  whoami.c
+
+ifeq ($(HAVE_SASL), 1)
+SRCS		+= saslio.c
+endif
+
+ifeq ($(OS_ARCH),WINNT)
+SRCS		+= dllmain.c \
+                   mozock.c
+endif
+RELEASE_LIBS	= $(SHARED_LIBRARY) $(DLLLDAP)
+
+REALOBJS	= $(SRCS:.c=.$(OBJ_SUFFIX))
+OBJS		= $(addprefix $(OBJDIR_NAME)/, $(REALOBJS))
+
+DISTHDIR	= $(DIST)/public/ldap
+HDIR		= $(topsrcdir)/ldap/include
+
+LIBLDAP		= $(addprefix $(OBJDIR_NAME)/, $(LIB_PREFIX)$(LDAP_LIBNAME).$(LIB_SUFFIX))
+DLLLDAP		= $(addprefix $(OBJDIR_NAME)/, $(LIB_PREFIX)$(LDAP_LIBNAME).$(DLL_SUFFIX))
+
+INSTALLDIR	= $(DIST)/$(OBJDIR_NAME)
+
+include $(topsrcdir)/config/rules.mk
+
+GARBAGE 	+= $(LIBLDAP) $(DLLLDAP)
+
+LOCAL_INCLUDES  = -I$(PUBLIC)/nspr
+INCLUDES	+= -I$(DISTHDIR) -I$(HDIR) -I$(INSTALLDIR)/public
+
+ifeq ($(HAVE_SASL), 1)
+INCLUDES        += $(SASL_CFLAGS)
+endif
+
+DEFINES		+= $(DEFS) -UMOZILLA_CLIENT
+
+ifdef USE_PTHREADS
+DEFINES   += -DUSE_PTHREADS
+endif
+
+ifeq ($(OS_ARCH),WINNT)
+PLATFORMCFLAGS	= -DNEEDPROTOS
+else
+PLATFORMCFLAGS	= -DUSE_WAITPID -DNEEDPROTOS
+endif
+THREADS		=
+THREADSLIB	=
+
+ETCFILENAMES	= ldapfilter.conf \
+		  ldapfriendly \
+		  ldapsearchprefs.conf \
+		  ldaptemplates.conf \
+		  $(NULL)
+
+ETCDIR		= $(INSTALLDIR)/etc
+ETCFILES	= $(addprefix $(srcdir)/, $(ETCFILENAMES))
+
+#
+# if you want things to run in a different directory from where they
+# are installed, set this accordingly (this path gets compiled into a
+# few binaries). otherwise, leave it alone.
+#
+RUNTIMEETCDIR	= $(ETCDIR)
+
+#
+# shared library symbol export definitions
+#
+ifeq ($(USE_DLL_EXPORTS_FILE), 1)
+ifeq ($(OS_ARCH), WINNT)
+GENEXPORTS=cmd /c  $(PERL) $(topsrcdir)/ldap/build/genexports.pl
+else
+GENEXPORTS=$(PERL) $(topsrcdir)/ldap/build/genexports.pl
+endif
+
+# variable definitions for exported symbols
+ifeq ($(OS_ARCH), WINNT)
+        LDAP_EXPORT_DEFS= $(WIN_TOP_SRC)/ldap/libraries/msdos/winsock/nsldap32.def
+else
+ifeq ($(OS_ARCH), OS2)
+        LDAP_EXPORT_DEFS= $(OBJDIR_NAME)/libldap.def
+else
+        LDAP_EXPORT_DEFS= $(OBJDIR_NAME)/libldap.exp
+endif
+GARBAGE += $(LDAP_EXPORT_DEFS)
+endif
+
+LDAP_EXPORT_FLAGS=$(addprefix $(DLLEXPORTS_PREFIX), $(LDAP_EXPORT_DEFS))
+
+GENEXPARGS=$(BUILD_DEBUG) $(LDAPVERS_SUFFIX) $(LDAPVERS)
+endif # USE_DLL_EXPORTS_FILE
+
+ifeq ($(OS_ARCH), SunOS)
+EXTRA_LIBS = -L$(dist_libdir) -l$(LBER_LIBNAME)
+endif
+
+ifeq ($(OS_ARCH), IRIX)
+EXTRA_LIBS = -L$(dist_libdir) -l$(LBER_LIBNAME) $(OS_LIBS) -lc
+endif
+
+ifeq ($(OS_ARCH), Linux)
+EXTRA_LIBS = -L$(dist_libdir) -l$(LBER_LIBNAME)
+endif
+
+ifeq ($(OS_ARCH), WINNT)
+ifdef NS_USE_GCC
+EXTRA_DLL_LIBS=-L$(dist_libdir) -l$(LBER_LIBNAME)
+else
+EXTRA_LIBS =wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib \
+            comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib \
+            rpcrt4.lib uuid.lib winmm.lib
+EXTRA_LIBS += $(dist_libdir)/$(LDIF_LIBNAME).lib
+EXTRA_LIBS += $(dist_libdir)/$(LBER_LIBNAME).lib
+endif
+endif
+
+ifeq ($(OS_ARCH), OS2)
+EXTRA_LIBS = -L$(dist_libdir) -l$(LBER_LIBNAME) $(OS_LIBS)
+endif
+
+ifeq ($(OS_ARCH), OSF1)
+EXTRA_LIBS = -L$(dist_libdir) -l$(LBER_LIBNAME)
+EXTRA_LIBS += -L/usr/lib -lcxx -lpthread -lrt -lmach -lexc
+endif
+
+ifeq ($(OS_ARCH), AIX)
+EXTRA_LIBS = -L$(dist_libdir) -l$(LBER_LIBNAME)
+EXTRA_LIBS += -ldl -brtl -lpthreads -lc_r -lm
+endif
+
+ifeq ($(OS_ARCH), HP-UX)
+EXTRA_LIBS = -L$(dist_libdir) -l$(LBER_LIBNAME)
+ifdef USE_PTHREADS
+EXTRA_LIBS += -ldld -lm -lpthread
+else
+EXTRA_LIBS += -ldld -lm
+endif
+endif
+
+ifeq ($(OS_ARCH), Darwin)
+EXTRA_LIBS = -L$(dist_libdir) -l$(LBER_LIBNAME)
+endif
+
+ifeq ($(OS_ARCH), OpenVMS)
+EXTRA_LIBS = -L$(dist_libdir) -l$(LBER_LIBNAME) $(OS_LIBS)
+SHARED_LIBRARY_LIBS = $(dist_libdir)/lib$(LBER_LIBNAME).a
+endif
+
+ifeq ($(OS_ARCH), BeOS)
+EXTRA_LIBS = -L$(dist_libdir) -l$(LBER_LIBNAME) -lbe
+endif
+
+ifeq ($(OS_ARCH), FreeBSD)
+EXTRA_LIBS = -L$(dist_libdir) -l$(LBER_LIBNAME)
+endif
+
+ifeq ($(OS_ARCH), NetBSD)
+EXTRA_LIBS = -L$(dist_libdir) -l$(LBER_LIBNAME)
+endif
+
+ifeq ($(OS_ARCH), OpenBSD)
+EXTRA_LIBS = -L$(dist_libdir) -l$(LBER_LIBNAME) -pthread
+endif
+
+ifeq ($(OS_ARCH), DragonFly)
+EXTRA_LIBS = -L$(dist_libdir) -l$(LBER_LIBNAME)
+endif
+
+ifeq ($(HAVE_SASL), 1)
+EXTRA_LIBS += $(SASL_LINK)
+endif
+
+###########################################################################
+
+ifeq ($(USE_DLL_EXPORTS_FILE), 1)
+# recursive gmake rule to create exported symbols file
+$(LDAP_EXPORT_DEFS):: $(srcdir)/../libldap.ex
+ifeq ($(OS_ARCH), WINNT)
+	$(GENEXPORTS) Win32 $(srcdir)/../msdos/winsock/nsldap32.tdf $< $(GENEXPARGS) > $@
+else
+ifeq ($(OS_ARCH), OS2)
+	echo LIBRARY $(LDAP_LIBNAME) INITINSTANCE TERMINSTANCE > $@
+	echo PROTMODE >> $@
+	echo CODE    LOADONCALL MOVEABLE DISCARDABLE >> $@
+	echo DATA    PRELOAD MOVEABLE MULTIPLE NONSHARED >> $@
+	echo EXPORTS >> $@
+	$(GENEXPORTS) $(OS_ARCH) Standard $< $(GENEXPARGS) >> $@
+else
+	$(GENEXPORTS) $(OS_ARCH) Standard $< $(GENEXPARGS) > $@
+endif
+endif
+endif # USE_DLL_EXPORTS_FILE
+
+versiont.c:	Makefile.client Version.c
+	@$(RM) $@
+	@(u="$${USER-root}" v="$(shell cat ../../build/version)" d="$(shell pwd)" \
+	h="$(shell hostname)" t="$(shell date)"; $(SED) -e "s|%WHEN%|$${t}|" \
+	-e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
+	-e "s|%VERSION%|$${v}|" \
+	< Version.c > $@)
+
+# Set the default sources for the export target
+EXPDEPS = $(OBJDIR_NAME) $(LIBDIR) $(OBJS) $(LIBLDAP) $(DLLLDAP)
+# Remove the LIB source if on win32 and using MSVC
+# This avoids problems with -jX builds where 'link' will make both the
+# .dll and .lib files in one pass
+ifeq ($(OS_ARCH), WINNT)
+ifeq ($(LD),link)
+EXPDEPS = $(OBJDIR_NAME) $(LIBDIR) $(OBJS) $(DLLLDAP)
+endif
+endif
+
+export::	$(EXPDEPS)
+
+ltest::	$(LIBLDAP) test.o
+		$(LINK_EXE) test.o
+
+$(LIBDIR):
+	$(MKDIR) $(LIBDIR)
+
+$(LIBLDAP): $(OBJS) $(LIBDIR) $(LDAP_EXPORT_DEFS)
+	@echo ======= making $(LIBLDAP)
+ifdef SO_FILES_TO_REMOVE
+	-$(RM) $(SO_FILES_TO_REMOVE)
+endif
+ifneq (,$(filter AIX Linux HP-UX Darwin BeOS QNX NetBSD OSF1 OpenBSD, $(OS_ARCH)))
+	$(LINK_LIB)
+else
+ifeq ($(OS_ARCH),OS2)
+# create import library for OS/2
+	rm -f $@
+	$(IMPLIB) $@ $(LDAP_EXPORT_DEFS)
+else
+	$(LINK_LIB)
+endif
+endif
+
+$(DLLLDAP): $(OBJS) $(LIBDIR) $(LDAP_EXPORT_DEFS)
+	@echo ======= making $(DLLLDAP)
+ifdef SO_FILES_TO_REMOVE
+	-$(RM) $(SO_FILES_TO_REMOVE)
+endif
+	$(LINK_DLL) $(LDAP_EXPORT_FLAGS) $(EXTRA_LIBS)
+
+veryclean:: clean
+
+# the $(dist_bindir) line is for the mozilla client, which for reasons
+# unknown wants shared libraries in /bin also
+#
+# Set the default sources for the export target
+EXPDEPS2 = $(LIBLDAP) $(DLLLDAP)
+# Remove the LIB source if on win32 and using MSVC
+# This avoids problems with -jX builds where 'link' will make both the
+# .dll and .lib files in one pass
+ifeq ($(OS_ARCH), WINNT)
+ifeq ($(LD),link)
+EXPDEPS2 = $(DLLLDAP)
+endif
+endif
+
+export::	$(EXPDEPS2)
+ifdef MKSHLIB
+	$(INSTALL) -m 444 $(LIBLDAP) $(dist_libdir)
+	$(INSTALL) -m 444 $(DLLLDAP) $(dist_libdir)
+	$(INSTALL) -m 444 $(DLLLDAP) $(dist_bindir)
+endif
+ifeq ($(OS_ARCH), WINNT)
+	$(INSTALL) -m 444 $(LIBLDAP) $(dist_libdir)
+	$(INSTALL) -m 444 $(DLLLDAP) $(dist_libdir)
+endif
+	$(INSTALL) -m 444 $(ETCFILES) $(ETCDIR)
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/abandon.c
@@ -0,0 +1,303 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ *  Copyright (c) 1990 Regents of the University of Michigan.
+ *  All rights reserved.
+ */
+/*
+ *  abandon.c
+ */
+
+#if 0
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+static int do_abandon( LDAP *ld, int origid, int msgid,
+    LDAPControl **serverctrls, LDAPControl **clientctrls );
+static int nsldapi_send_abandon_message( LDAP *ld, LDAPConn *lc, 
+    BerElement *ber, int abandon_msgid );
+
+/*
+ * ldap_abandon - perform an ldap abandon operation. Parameters:
+ *
+ *	ld		LDAP descriptor
+ *	msgid		The message id of the operation to abandon
+ *
+ * ldap_abandon returns 0 if everything went ok, -1 otherwise.
+ *
+ * Example:
+ *	ldap_abandon( ld, msgid );
+ */
+int
+LDAP_CALL
+ldap_abandon( LDAP *ld, int msgid )
+{
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_abandon %d\n", msgid, 0, 0 );
+	LDAPDebug( LDAP_DEBUG_TRACE, "4e65747363617065\n", msgid, 0, 0 );
+	LDAPDebug( LDAP_DEBUG_TRACE, "466f726576657221\n", msgid, 0, 0 );
+
+	if ( ldap_abandon_ext( ld, msgid, NULL, NULL ) == LDAP_SUCCESS ) {
+	    return( 0 );
+	}
+
+	return( -1 );
+}
+
+
+/*
+ * LDAPv3 extended abandon.
+ * Returns an LDAP error code.
+ */
+int
+LDAP_CALL
+ldap_abandon_ext( LDAP *ld, int msgid, LDAPControl **serverctrls,
+	LDAPControl **clientctrls )
+{
+	int	rc;
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_abandon_ext %d\n", msgid, 0, 0 );
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( LDAP_PARAM_ERROR );
+	}
+
+	LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK );
+	LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
+	rc = do_abandon( ld, msgid, msgid, serverctrls, clientctrls );
+
+	/*
+	 * XXXmcs should use cache function pointers to hook in memcache
+	 */
+	ldap_memcache_abandon( ld, msgid );
+
+	LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
+	LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
+
+	return( rc );
+}
+
+
+/*
+ * Abandon all outstanding requests for msgid (included child requests
+ * spawned when chasing referrals).  This function calls itself recursively.
+ * No locking is done is this function so it must be done by the caller.
+ * Returns an LDAP error code and sets it in LDAP *ld as well
+ */
+static int
+do_abandon( LDAP *ld, int origid, int msgid, LDAPControl **serverctrls,
+    LDAPControl **clientctrls )
+{
+	BerElement	*ber;
+	int		i, bererr, lderr, sendabandon;
+	LDAPRequest	*lr = NULL;
+
+	/*
+	 * An abandon request looks like this:
+	 *	AbandonRequest ::= MessageID
+	 */
+	LDAPDebug( LDAP_DEBUG_TRACE, "do_abandon origid %d, msgid %d\n",
+		origid, msgid, 0 );
+
+	/* optimistic */
+	lderr = LDAP_SUCCESS;	
+
+        /*
+	 * Find the request that we are abandoning.  Don't send an
+	 * abandon message unless there is something to abandon.
+	 */
+        sendabandon = 0;
+	for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) {
+		if ( lr->lr_msgid == msgid ) {	/* this message */
+			if ( origid == msgid && lr->lr_parent != NULL ) {
+				/* don't let caller abandon child requests! */
+				lderr = LDAP_PARAM_ERROR;
+				goto set_errorcode_and_return;
+			}
+			if ( lr->lr_status == LDAP_REQST_INPROGRESS ) {
+			 	/*
+				 * We only need to send an abandon message if
+				 * the request is in progress.
+				 */
+			    sendabandon = 1;
+			}
+			break;
+		}
+		if ( lr->lr_origid == msgid ) {	/* child:  abandon it */
+			(void)do_abandon( ld, msgid, lr->lr_msgid,
+			      serverctrls, clientctrls );
+			/* we ignore errors from child abandons... */
+		}
+	}
+
+	if ( ldap_msgdelete( ld, msgid ) == 0 ) {
+		/* we had all the results and deleted them */
+		goto set_errorcode_and_return;
+	}
+
+	if ( lr != NULL && sendabandon ) {
+		/* create a message to send */
+		if (( lderr = nsldapi_alloc_ber_with_options( ld, &ber )) ==
+		    LDAP_SUCCESS ) {
+			int	abandon_msgid;
+
+			LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK );
+			abandon_msgid = ++ld->ld_msgid;
+			LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK );
+#ifdef CLDAP
+			if ( ld->ld_dbp->sb_naddr > 0 ) {
+				bererr = ber_printf( ber, "{isti",
+				    abandon_msgid, ld->ld_cldapdn,
+				    LDAP_REQ_ABANDON, msgid );
+			} else {
+#endif /* CLDAP */
+				bererr = ber_printf( ber, "{iti",
+				    abandon_msgid, LDAP_REQ_ABANDON, msgid );
+#ifdef CLDAP
+			}
+#endif /* CLDAP */
+
+			if ( bererr == -1 ||
+			    ( lderr = nsldapi_put_controls( ld, serverctrls,
+			    1, ber )) != LDAP_SUCCESS ) {
+				lderr = LDAP_ENCODING_ERROR;
+				ber_free( ber, 1 );
+			} else {
+				/* try to send the message */
+				lderr = nsldapi_send_abandon_message( ld,
+				    lr->lr_conn, ber, abandon_msgid );
+			}
+		}
+	}
+
+	if ( lr != NULL ) {
+		/*
+		 * Always call nsldapi_free_connection() so that the connection's
+		 * ref count is correctly decremented.  It is OK to always pass
+		 * 1 for the "unbind" parameter because doing so will only affect
+		 * connections that resulted from a child request (because the
+		 * default connection's ref count never goes to zero).
+		 */
+		nsldapi_free_connection( ld, lr->lr_conn, NULL, NULL,
+			0 /* do not force */, 1 /* send unbind before closing */ );
+
+		/*
+		 * Free the entire request chain if we finished abandoning everything.
+		 */
+		if ( origid == msgid ) {
+			nsldapi_free_request( ld, lr, 0 );
+		}
+	}
+
+	/*
+	 * Record the abandoned message ID (used to discard any server responses
+	 * that arrive later).
+	 */
+	LDAP_MUTEX_LOCK( ld, LDAP_ABANDON_LOCK );
+	if ( ld->ld_abandoned == NULL ) {
+		if ( (ld->ld_abandoned = (int *)NSLDAPI_MALLOC( 2
+		    * sizeof(int) )) == NULL ) {
+			lderr = LDAP_NO_MEMORY;
+			LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
+			goto set_errorcode_and_return;
+		}
+		i = 0;
+	} else {
+		for ( i = 0; ld->ld_abandoned[i] != -1; i++ )
+			;	/* NULL */
+		if ( (ld->ld_abandoned = (int *)NSLDAPI_REALLOC( (char *)
+		    ld->ld_abandoned, (i + 2) * sizeof(int) )) == NULL ) {
+			lderr = LDAP_NO_MEMORY;
+			LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
+			goto set_errorcode_and_return;
+		}
+	}
+	ld->ld_abandoned[i] = msgid;
+	ld->ld_abandoned[i + 1] = -1;
+	LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
+
+set_errorcode_and_return:
+	LDAP_SET_LDERRNO( ld, lderr, NULL, NULL );
+	return( lderr );
+}
+
+/*
+ * Try to send the abandon message that is encoded in ber.  Returns an
+ * LDAP result code.
+ */
+static int
+nsldapi_send_abandon_message( LDAP *ld, LDAPConn *lc, BerElement *ber,
+    int abandon_msgid )
+{
+	int	lderr = LDAP_SUCCESS;
+	int	err = 0;
+
+	err = nsldapi_send_ber_message( ld, lc->lconn_sb,
+	    ber, 1 /* free ber */, 0 /* will not handle EPIPE */ );
+	if ( err == -2 ) {
+		/*
+		 * "Would block" error.  Queue the abandon as
+		 * a pending request.
+		 */
+		LDAPRequest	*lr;
+
+		lr = nsldapi_new_request( lc, ber, abandon_msgid,
+		    0 /* no response expected */ );
+		if ( lr == NULL ) {
+			lderr = LDAP_NO_MEMORY;
+			ber_free( ber, 1 );
+		} else {
+			lr->lr_status = LDAP_REQST_WRITING;
+			nsldapi_queue_request_nolock( ld, lr );
+			++lc->lconn_pending_requests;
+			nsldapi_iostatus_interest_write( ld,
+			    lc->lconn_sb );
+		}
+	} else if ( err != 0 ) {
+		/*
+		 * Fatal error (not a "would block" error).
+		 */
+		lderr = LDAP_SERVER_DOWN;
+		ber_free( ber, 1 );
+	}
+
+	return( lderr );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/add.c
@@ -0,0 +1,225 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ *  Copyright (c) 1990 Regents of the University of Michigan.
+ *  All rights reserved.
+ */
+/*
+ *  add.c
+ */
+
+#if 0
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+/*
+ * ldap_add - initiate an ldap add operation.  Parameters:
+ *
+ *	ld		LDAP descriptor
+ *	dn		DN of the entry to add
+ *	mods		List of attributes for the entry.  This is a null-
+ *			terminated array of pointers to LDAPMod structures.
+ *			only the type and values in the structures need be
+ *			filled in.
+ *
+ * Example:
+ *	LDAPMod	*attrs[] = { 
+ *			{ 0, "cn", { "babs jensen", "babs", 0 } },
+ *			{ 0, "sn", { "jensen", 0 } },
+ *			{ 0, "objectClass", { "person", 0 } },
+ *			0
+ *		}
+ *	msgid = ldap_add( ld, dn, attrs );
+ */
+int
+LDAP_CALL
+ldap_add( LDAP *ld, const char *dn, LDAPMod **attrs )
+{
+	int		msgid;
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_add\n", 0, 0, 0 );
+
+	if ( ldap_add_ext( ld, dn, attrs, NULL, NULL, &msgid )
+	    == LDAP_SUCCESS ) {
+		return( msgid );
+	} else {
+		return( -1 );	/* error is in ld handle */
+	}
+}
+
+
+/*
+ * LDAPv3 extended add.
+ * Returns an LDAP error code.
+ */
+int
+LDAP_CALL
+ldap_add_ext( LDAP *ld, const char *dn, LDAPMod **attrs,
+    LDAPControl **serverctrls, LDAPControl **clientctrls, int *msgidp )
+{
+	BerElement	*ber;
+	int		i, rc, lderr;
+
+	/*
+	 * An add request looks like this:
+	 *	AddRequest ::= SEQUENCE {
+	 *		entry	DistinguishedName,
+	 *		attrs	SEQUENCE OF SEQUENCE {
+	 *			type	AttributeType,
+	 *			values	SET OF AttributeValue
+	 *		}
+	 *	}
+	 */
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_add_ext\n", 0, 0, 0 );
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( LDAP_PARAM_ERROR );
+	}
+
+	if ( !NSLDAPI_VALID_LDAPMESSAGE_POINTER( msgidp )) 
+        {
+		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+		return( LDAP_PARAM_ERROR );
+	}
+	if ( !NSLDAPI_VALID_NONEMPTY_LDAPMOD_ARRAY( attrs )
+	    || msgidp == NULL ) {
+		lderr = LDAP_PARAM_ERROR;
+		LDAP_SET_LDERRNO( ld, lderr, NULL, NULL );
+		return( lderr );
+	}
+
+	if ( dn == NULL ) {
+		dn = "";
+	}
+
+	LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK );
+	*msgidp = ++ld->ld_msgid;
+	LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK );
+
+	/* see if we should add to the cache */
+	if ( ld->ld_cache_on && ld->ld_cache_add != NULL ) {
+		LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK );
+		if ( (rc = (ld->ld_cache_add)( ld, *msgidp, LDAP_REQ_ADD, dn,
+		    attrs )) != 0 ) {
+			*msgidp = rc;
+			LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+			return( LDAP_SUCCESS );
+		}
+		LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+	}
+
+	/* create a message to send */
+	if (( lderr = nsldapi_alloc_ber_with_options( ld, &ber ))
+	    != LDAP_SUCCESS ) {
+		return( lderr );
+	}
+
+	if ( ber_printf( ber, "{it{s{", *msgidp, LDAP_REQ_ADD, dn )
+	    == -1 ) {
+		lderr = LDAP_ENCODING_ERROR;
+		LDAP_SET_LDERRNO( ld, lderr, NULL, NULL );
+		ber_free( ber, 1 );
+		return( lderr );
+	}
+
+	/* for each attribute in the entry... */
+	for ( i = 0; attrs[i] != NULL; i++ ) {
+		if ( ( attrs[i]->mod_op & LDAP_MOD_BVALUES) != 0 ) {
+			rc = ber_printf( ber, "{s[V]}", attrs[i]->mod_type,
+			    attrs[i]->mod_bvalues );
+		} else {
+			rc = ber_printf( ber, "{s[v]}", attrs[i]->mod_type,
+			    attrs[i]->mod_values );
+		}
+		if ( rc == -1 ) {
+			lderr = LDAP_ENCODING_ERROR;
+			LDAP_SET_LDERRNO( ld, lderr, NULL, NULL );
+			ber_free( ber, 1 );
+			return( lderr );
+		}
+	}
+
+	if ( ber_printf( ber, "}}" ) == -1 ) {
+		lderr = LDAP_ENCODING_ERROR;
+		LDAP_SET_LDERRNO( ld, lderr, NULL, NULL );
+		ber_free( ber, 1 );
+		return( lderr );
+	}
+
+	if (( lderr = nsldapi_put_controls( ld, serverctrls, 1, ber ))
+	    != LDAP_SUCCESS ) {
+		ber_free( ber, 1 );
+		return( lderr );
+	}
+
+	/* send the message */
+	rc = nsldapi_send_initial_request( ld, *msgidp, LDAP_REQ_ADD,
+						(char *) dn, ber );
+	*msgidp = rc;
+	return( rc < 0 ? LDAP_GET_LDERRNO( ld, NULL, NULL ) : LDAP_SUCCESS );
+}
+
+int
+LDAP_CALL
+ldap_add_s( LDAP *ld, const char *dn, LDAPMod **attrs )
+{
+	return( ldap_add_ext_s( ld, dn, attrs, NULL, NULL ));
+}
+
+int LDAP_CALL
+ldap_add_ext_s( LDAP *ld, const char *dn, LDAPMod **attrs,
+	LDAPControl **serverctrls, LDAPControl **clientctrls )
+{
+	int		err, msgid;
+	LDAPMessage	*res;
+
+	if (( err = ldap_add_ext( ld, dn, attrs, serverctrls, clientctrls,
+	    &msgid )) != LDAP_SUCCESS ) {
+		return( err );
+	}
+
+	if ( ldap_result( ld, msgid, 1, (struct timeval *)NULL, &res ) == -1 ) {
+		return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+	}
+
+	return( ldap_result2error( ld, res, 1 ) );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/authzidctrl.c
@@ -0,0 +1,157 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Sun LDAP C SDK.
+ *
+ * The Initial Developer of the Original Code is Sun Microsystems, Inc.
+ *
+ * Portions created by Sun Microsystems, Inc are Copyright (C) 2005
+ * Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Contributor(s): abobrov@sun.com
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ldap-int.h"
+
+/* ldap_create_authzid_control:
+
+Parameters are  
+
+ld              LDAP pointer to the desired connection 
+
+ctl_iscritical  Indicates whether the control is critical of not. 
+                If this field is non-zero, the operation will only be 
+                carried out if the control is recognized by the server
+                and/or client
+
+ctrlp           the address of a place to put the constructed control 
+*/
+
+int
+LDAP_CALL
+ldap_create_authzid_control ( 	
+							 LDAP        *ld, 
+							 const char  ctl_iscritical,
+							 LDAPControl **ctrlp   
+							)
+{
+	int				rc;
+	
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( LDAP_PARAM_ERROR );
+	}
+	
+	if ( ctrlp == NULL ) {
+		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+		return ( LDAP_PARAM_ERROR );
+	}
+	
+	rc = nsldapi_build_control( LDAP_CONTROL_AUTHZID_REQ, 
+								NULL, 0, ctl_iscritical, ctrlp );
+	
+	LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+	return( rc );
+}
+
+/* ldap_parse_authzid_control:
+
+Parameters are  
+
+ld              LDAP pointer to the desired connection 
+
+ctrlp           An array of controls obtained from calling  
+                ldap_parse_result on the set of results 
+                returned by the server     
+
+authzid         authorization identity, as defined in 
+                RFC 2829, section 9.
+*/
+
+int
+LDAP_CALL
+ldap_parse_authzid_control ( 	
+							LDAP        *ld, 
+							LDAPControl **ctrlp,  
+							char        **authzid
+						   )
+{
+	int			i, foundAUTHZIDControl;
+	char        *authzidp = NULL;
+	LDAPControl *AUTHZIDCtrlp = NULL;
+	
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) ) {
+	    return( LDAP_PARAM_ERROR );
+	}
+	
+	/* find the control in the list of controls if it exists */
+	if ( ctrlp == NULL ) {
+		LDAP_SET_LDERRNO( ld, LDAP_CONTROL_NOT_FOUND, NULL, NULL );
+		return ( LDAP_CONTROL_NOT_FOUND );
+	} 
+	foundAUTHZIDControl = 0;
+	for ( i = 0; (( ctrlp[i] != NULL ) && ( !foundAUTHZIDControl )); i++ ) {
+		foundAUTHZIDControl = !strcmp( ctrlp[i]->ldctl_oid, 
+									  LDAP_CONTROL_AUTHZID_RES );
+	}
+	
+	/*
+	 * The control is only included in a bind response if the resultCode 
+	 * for the bind operation is success.
+	 */
+	if ( !foundAUTHZIDControl ) {
+		LDAP_SET_LDERRNO( ld, LDAP_CONTROL_NOT_FOUND, NULL, NULL );
+		return ( LDAP_CONTROL_NOT_FOUND );
+	} else {
+		/* let local var point to the control */
+		AUTHZIDCtrlp = ctrlp[i-1];			
+	}
+	
+	/*
+	 * If the bind request succeeded and resulted in an identity (not anonymous), 
+	 * the controlValue contains the authorization identity (authzid), as
+	 * defined in [AUTH] section 9, granted to the requestor.  If the bind
+	 * request resulted in an anonymous association, the controlValue field
+	 * is a string of zero length.  If the bind request resulted in more
+	 * than one authzid, the primary authzid is returned in the controlValue
+	 * field.
+	 */
+	if ( AUTHZIDCtrlp && AUTHZIDCtrlp->ldctl_value.bv_val && 
+		 AUTHZIDCtrlp->ldctl_value.bv_len ) {
+		authzidp = ( (char *)NSLDAPI_MALLOC( 
+							( AUTHZIDCtrlp->ldctl_value.bv_len + 1 ) ) );
+		if ( authzidp == NULL ) {
+			LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+			return( LDAP_NO_MEMORY );
+		}
+		STRLCPY( authzidp, AUTHZIDCtrlp->ldctl_value.bv_val, 
+				 ( AUTHZIDCtrlp->ldctl_value.bv_len + 1 ) );
+		*authzid = authzidp;
+	} else {
+		authzid = NULL;
+	}
+	
+	return( LDAP_SUCCESS );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/bind.c
@@ -0,0 +1,170 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ *  bind.c
+ */
+
+#if 0
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+/*
+ * ldap_bind - bind to the ldap server. The dn and password
+ * of the entry to which to bind are supplied, along with the authentication
+ * method to use.  The msgid of the bind request is returned on success,
+ * -1 if there's trouble.  Note, the kerberos support assumes the user already
+ * has a valid tgt for now.  ldap_result() should be called to find out the
+ * outcome of the bind request.
+ *
+ * Example:
+ *	ldap_bind( ld, "cn=manager, o=university of michigan, c=us", "secret",
+ *	    LDAP_AUTH_SIMPLE )
+ */
+
+int
+LDAP_CALL
+ldap_bind( LDAP *ld, const char *dn, const char *passwd, int authmethod )
+{
+	/*
+	 * The bind request looks like this:
+	 *	BindRequest ::= SEQUENCE {
+	 *		version		INTEGER,
+	 *		name		DistinguishedName,	 -- who
+	 *		authentication	CHOICE {
+	 *			simple		[0] OCTET STRING -- passwd
+	 *		}
+	 *	}
+	 * all wrapped up in an LDAPMessage sequence.
+	 */
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_bind\n", 0, 0, 0 );
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( -1 );
+	}
+
+	switch ( authmethod ) {
+	case LDAP_AUTH_SIMPLE:
+		return( ldap_simple_bind( ld, dn, passwd ) );
+
+	default:
+		LDAP_SET_LDERRNO( ld, LDAP_AUTH_UNKNOWN, NULL, NULL );
+		return( -1 );
+	}
+}
+
+/*
+ * ldap_bind_s - bind to the ldap server.  The dn and password
+ * of the entry to which to bind are supplied, along with the authentication
+ * method to use.  This routine just calls whichever bind routine is
+ * appropriate and returns the result of the bind (e.g. LDAP_SUCCESS or
+ * some other error indication).  Note, the kerberos support assumes the
+ * user already has a valid tgt for now.
+ *
+ * Examples:
+ *	ldap_bind_s( ld, "cn=manager, o=university of michigan, c=us",
+ *	    "secret", LDAP_AUTH_SIMPLE )
+ *	ldap_bind_s( ld, "cn=manager, o=university of michigan, c=us",
+ *	    NULL, LDAP_AUTH_KRBV4 )
+ */
+int
+LDAP_CALL
+ldap_bind_s( LDAP *ld, const char *dn, const char *passwd, int authmethod )
+{
+	int	err;
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_bind_s\n", 0, 0, 0 );
+
+	switch ( authmethod ) {
+	case LDAP_AUTH_SIMPLE:
+		return( ldap_simple_bind_s( ld, dn, passwd ) );
+
+	default:
+		err = LDAP_AUTH_UNKNOWN;
+		LDAP_SET_LDERRNO( ld, err, NULL, NULL );
+		return( err );
+	}
+}
+
+
+void
+LDAP_CALL
+ldap_set_rebind_proc( LDAP *ld, LDAP_REBINDPROC_CALLBACK *rebindproc,
+    void *arg )
+{
+	if ( ld == NULL ) {
+		if ( !nsldapi_initialized ) {
+			nsldapi_initialize_defaults();
+		}
+		ld = &nsldapi_ld_defaults;
+	}
+
+	if ( NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		LDAP_MUTEX_LOCK( ld, LDAP_OPTION_LOCK );
+		ld->ld_rebind_fn = rebindproc;
+		ld->ld_rebind_arg = arg;
+		LDAP_MUTEX_UNLOCK( ld, LDAP_OPTION_LOCK );
+	}
+}
+
+
+/*
+ * return a pointer to the bind DN for the default connection (a copy is
+ * not made).  If there is no bind DN available, NULL is returned.
+ */
+char *
+nsldapi_get_binddn( LDAP *ld )
+{
+	char	*binddn;
+
+	binddn = NULL;	/* default -- assume they are not bound */
+
+	LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK );
+	if ( NULL != ld->ld_defconn && LDAP_CONNST_CONNECTED ==
+	    ld->ld_defconn->lconn_status && ld->ld_defconn->lconn_bound ) {
+		if (( binddn = ld->ld_defconn->lconn_binddn ) == NULL ) {
+			binddn = "";
+		}
+	}
+	LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
+
+	return( binddn );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/cache.c
@@ -0,0 +1,145 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ *  Copyright (c) 1993 The Regents of the University of Michigan.
+ *  All rights reserved.
+ */
+/*
+ *  cache.c - generic caching support for LDAP
+ */
+
+#include "ldap-int.h"
+
+/*
+ * ldap_cache_flush - flush part of the LDAP cache. returns an
+ * ldap error code (LDAP_SUCCESS, LDAP_NO_SUCH_OBJECT, etc.).
+ */
+
+int
+LDAP_CALL
+ldap_cache_flush( LDAP *ld, const char *dn, const char *filter )
+{
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( LDAP_PARAM_ERROR );
+	}
+
+	if ( dn == NULL ) {
+		dn = "";
+	}
+
+	return( (ld->ld_cache_flush)( ld, dn, filter ) );
+}
+
+/*
+ * nsldapi_add_result_to_cache - add an ldap entry we just read off the network
+ * to the ldap cache. this routine parses the ber for the entry and
+ * constructs the appropriate add request. this routine calls the
+ * cache add routine to actually add the entry.
+ */
+
+void
+nsldapi_add_result_to_cache( LDAP *ld, LDAPMessage *m )
+{
+	char		*dn;
+	LDAPMod		**mods;
+	int		i, max, rc;
+	char		*a;
+	BerElement	*ber;
+	char		buf[50];
+	struct berval	bv;
+	struct berval	*bvp[2];
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "=> nsldapi_add_result_to_cache id %d type %d\n",
+	    m->lm_msgid, m->lm_msgtype, 0 );
+	if ( m->lm_msgtype != LDAP_RES_SEARCH_ENTRY ||
+	    ld->ld_cache_add == NULL ) {
+		LDAPDebug( LDAP_DEBUG_TRACE,
+		    "<= nsldapi_add_result_to_cache not added\n", 0, 0, 0 );
+		return;
+	}
+
+#define GRABSIZE	5
+
+	dn = ldap_get_dn( ld, m );
+	mods = (LDAPMod **)NSLDAPI_MALLOC( GRABSIZE * sizeof(LDAPMod *) );
+	max = GRABSIZE;
+	for ( i = 0, a = ldap_first_attribute( ld, m, &ber ); a != NULL;
+	    a = ldap_next_attribute( ld, m, ber ), i++ ) {
+		if ( i == (max - 1) ) {
+			max += GRABSIZE;
+			mods = (LDAPMod **)NSLDAPI_REALLOC( mods,
+			    sizeof(LDAPMod *) * max );
+		}
+
+		mods[i] = (LDAPMod *)NSLDAPI_CALLOC( 1, sizeof(LDAPMod) );
+		mods[i]->mod_op = LDAP_MOD_BVALUES;
+		mods[i]->mod_type = a;
+		mods[i]->mod_bvalues = ldap_get_values_len( ld, m, a );
+	}
+	if ( ber != NULL ) {
+		ber_free( ber, 0 );
+	}
+	if (( rc = LDAP_GET_LDERRNO( ld, NULL, NULL )) != LDAP_SUCCESS ) {
+		LDAPDebug( LDAP_DEBUG_TRACE,
+		    "<= nsldapi_add_result_to_cache error: failed to construct mod list (%s)\n",
+		    ldap_err2string( rc ), 0, 0 );
+		ldap_mods_free( mods, 1 );
+		return;
+	}
+
+	/* update special cachedtime attribute */
+	if ( i == (max - 1) ) {
+		max++;
+		mods = (LDAPMod **)NSLDAPI_REALLOC( mods,
+		    sizeof(LDAPMod *) * max );
+	}
+	mods[i] = (LDAPMod *)NSLDAPI_CALLOC( 1, sizeof(LDAPMod) );
+	mods[i]->mod_op = LDAP_MOD_BVALUES;
+	mods[i]->mod_type = "cachedtime";
+	sprintf( buf, "%ld", time( NULL ) );
+	bv.bv_val = buf;
+	bv.bv_len = strlen( buf );
+	bvp[0] = &bv;
+	bvp[1] = NULL;
+	mods[i]->mod_bvalues = bvp;
+	mods[++i] = NULL;
+
+	/* msgid of -1 means don't send the result */
+	rc = (ld->ld_cache_add)( ld, -1, m->lm_msgtype, dn, mods );
+	LDAPDebug( LDAP_DEBUG_TRACE,
+	    "<= nsldapi_add_result_to_cache added (rc %d)\n", rc, 0, 0 );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/charray.c
@@ -0,0 +1,248 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/* charray.c - routines for dealing with char * arrays */
+
+
+#include "ldap-int.h" 
+ 
+/*
+ * Add s at the end of the array of strings *a.
+ * Return 0 for success, -1 for failure.
+ */
+int
+LDAP_CALL
+ldap_charray_add(
+    char	***a,
+    char	*s
+)
+{
+	int	n;
+
+	if ( *a == NULL ) {
+		*a = (char **)NSLDAPI_MALLOC( 2 * sizeof(char *) );
+		if ( *a == NULL ) {
+			return -1;
+		}
+		n = 0;
+	} else {
+		for ( n = 0; *a != NULL && (*a)[n] != NULL; n++ ) {
+			;	/* NULL */
+		}
+
+		*a = (char **)NSLDAPI_REALLOC( (char *) *a,
+		    (n + 2) * sizeof(char *) );
+		if ( *a == NULL ) {
+			return -1;
+		}
+	}
+
+	(*a)[n++] = s;
+	(*a)[n] = NULL;
+	return 0;
+}
+
+/*
+ * Add array of strings s at the end of the array of strings *a.
+ * Return 0 for success, -1 for failure.
+ */
+int
+LDAP_CALL
+ldap_charray_merge(
+    char	***a,
+    char	**s
+)
+{
+	int	i, n, nn;
+
+	if ( (s == NULL) || (s[0] == NULL) )
+	    return 0;
+
+	for ( n = 0; *a != NULL && (*a)[n] != NULL; n++ ) {
+		;	/* NULL */
+	}
+	for ( nn = 0; s[nn] != NULL; nn++ ) {
+		;	/* NULL */
+	}
+
+	*a = (char **)NSLDAPI_REALLOC( (char *) *a,
+	    (n + nn + 1) * sizeof(char *) );
+	if ( *a == NULL ) {
+		return -1;
+	}
+
+	for ( i = 0; i < nn; i++ ) {
+		(*a)[n + i] = s[i];
+	}
+	(*a)[n + nn] = NULL;
+	return 0;
+}
+
+void
+LDAP_CALL
+ldap_charray_free( char **array )
+{
+	char	**a;
+
+	if ( array == NULL ) {
+		return;
+	}
+
+	for ( a = array; *a != NULL; a++ ) {
+		if ( *a != NULL ) {
+			NSLDAPI_FREE( *a );
+		}
+	}
+	NSLDAPI_FREE( (char *) array );
+}
+
+int
+LDAP_CALL
+ldap_charray_inlist(
+    char	**a,
+    char	*s
+)
+{
+	int	i;
+
+	if ( a == NULL )
+		return( 0 );
+
+	for ( i = 0; a[i] != NULL; i++ ) {
+		if ( strcasecmp( s, a[i] ) == 0 ) {
+			return( 1 );
+		}
+	}
+
+	return( 0 );
+}
+
+/*
+ * Duplicate the array of strings a, return NULL upon any memory failure.
+ */
+char **
+LDAP_CALL
+ldap_charray_dup( char **a )
+{
+	int	i;
+	char	**new;
+
+	for ( i = 0; a[i] != NULL; i++ )
+		;	/* NULL */
+
+	new = (char **)NSLDAPI_MALLOC( (i + 1) * sizeof(char *) );
+	if ( new == NULL ) {
+		return NULL;
+	}
+
+	for ( i = 0; a[i] != NULL; i++ ) {
+		new[i] = nsldapi_strdup( a[i] );
+		if ( new[i] == NULL ) {
+			int	j;
+
+			for ( j = 0; j < i; j++ )
+			    NSLDAPI_FREE( new[j] );
+			NSLDAPI_FREE( new );
+			return NULL;
+		}
+	}
+	new[i] = NULL;
+
+	return( new );
+}
+
+/*
+ * Tokenize the string str, return NULL upon any memory failure.
+ * XXX: on many platforms this function is not thread safe because it
+ *	uses strtok().
+ */
+char **
+LDAP_CALL
+ldap_str2charray( char *str, char *brkstr )
+     /* This implementation fails if brkstr contains multibyte characters.
+        But it works OK if str is UTF-8 and brkstr is 7-bit ASCII.
+      */
+{
+	char	**res;
+	char	*s;
+	int	i;
+#ifdef HAVE_STRTOK_R    /* defined in portable.h */
+	char	*lasts; 
+#endif
+
+	i = 1;
+	for ( s = str; *s; s++ ) {
+		if ( strchr( brkstr, *s ) != NULL ) {
+			i++;
+		}
+	}
+
+	res = (char **)NSLDAPI_MALLOC( (i + 1) * sizeof(char *) );
+	if ( res == NULL ) {
+		return NULL;
+	}
+	i = 0;
+	for ( s = STRTOK( str, brkstr, &lasts ); s != NULL; s = STRTOK( NULL,
+	    brkstr, &lasts ) ) {
+		res[i++] = nsldapi_strdup( s );
+		if ( res[i - 1] == NULL ) {
+			int	j;
+
+			for ( j = 0; j < (i - 1); j++ )
+			    NSLDAPI_FREE( res[j] );
+			NSLDAPI_FREE( res );
+			return NULL;
+		}
+	}
+	res[i] = NULL;
+
+	return( res );
+}
+
+int
+LDAP_CALL
+ldap_charray_position( char **a, char *s )
+{
+	int     i;
+
+	for ( i = 0; a[i] != NULL; i++ ) {
+		if ( strcasecmp( s, a[i] ) == 0 ) {
+			return( i );
+		}
+	}
+
+	return( -1 );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/charset.c
@@ -0,0 +1,1845 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ *  Copyright (c) 1995 Regents of the University of Michigan.
+ *  All rights reserved.
+ */
+/*
+ *  charset.c
+ */
+
+#include "ldap-int.h"
+
+#ifdef STR_TRANSLATION
+
+void
+ldap_set_string_translators( LDAP *ld, BERTranslateProc encode_proc,
+	BERTranslateProc decode_proc )
+{
+	if ( ld == NULL ) {
+		if ( !nsldapi_initialized ) {
+			nsldapi_initialize_defaults();
+		}
+		ld = &nsldapi_ld_defaults;
+	}
+
+	if ( NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		ld->ld_lber_encode_translate_proc = encode_proc;
+		ld->ld_lber_decode_translate_proc = decode_proc;
+	}
+}
+
+
+void
+ldap_enable_translation( LDAP *ld, LDAPMessage *entry, int enable )
+{
+	char	*optionsp;
+
+	if ( ld == NULL ) {
+		if ( !nsldapi_initialized ) {
+			nsldapi_initialize_defaults();
+		}
+		ld = &nsldapi_ld_defaults;
+	}
+
+	optionsp = ( entry == NULLMSG ) ? &ld->ld_lberoptions :
+	    &entry->lm_ber->ber_options;
+		
+	if ( enable ) {
+		*optionsp |= LBER_OPT_TRANSLATE_STRINGS;
+	} else {
+		*optionsp &= ~LBER_OPT_TRANSLATE_STRINGS;
+	}
+}
+
+
+int
+ldap_translate_from_t61( LDAP *ld, char **bufp, unsigned long *lenp,
+    int free_input )
+{
+	if ( ld->ld_lber_decode_translate_proc == NULL ) {
+		return( LDAP_SUCCESS );
+	}
+	    
+	return( (*ld->ld_lber_decode_translate_proc)( bufp, lenp, free_input ));
+}
+
+
+int
+ldap_translate_to_t61( LDAP *ld, char **bufp, unsigned long *lenp,
+    int free_input )
+{
+	if ( ld->ld_lber_encode_translate_proc == NULL ) {
+		return( LDAP_SUCCESS );
+	}
+	    
+	return( (*ld->ld_lber_encode_translate_proc)( bufp, lenp, free_input ));
+}
+
+
+/*
+ ** Character translation routine notes:
+ *
+ * On entry:  bufp points to a "string" to be converted (not necessarily
+ *  zero-terminated) and buflenp points to the length of the buffer.
+ *
+ * On exit:  bufp should point to a malloc'd result.  If free_input is
+ *  non-zero then the original bufp will be freed.  *buflenp should be
+ *  set to the new length.  Zero bytes in the input buffer must be left
+ *  as zero bytes.
+ *
+ * Return values: any ldap error code (LDAP_SUCCESS if all goes well).
+ */
+
+
+#ifdef LDAP_CHARSET_8859
+
+#if LDAP_CHARSET_8859 == 88591
+#define ISO_8859 1
+#elif LDAP_CHARSET_8859 == 88592
+#define ISO_8859 2
+#elif LDAP_CHARSET_8859 == 88593
+#define ISO_8859 3
+#elif LDAP_CHARSET_8859 == 88594
+#define ISO_8859 4
+#elif LDAP_CHARSET_8859 == 88595
+#define ISO_8859 5
+#elif LDAP_CHARSET_8859 == 88596
+#define ISO_8859 6
+#elif LDAP_CHARSET_8859 == 88597
+#define ISO_8859 7
+#elif LDAP_CHARSET_8859 == 88598
+#define ISO_8859 8
+#elif LDAP_CHARSET_8859 == 88599
+#define ISO_8859 9
+#elif LDAP_CHARSET_8859 == 885910
+#define ISO_8859 10
+#else
+#define ISO_8859 0
+#endif
+
+/*
+ * the following ISO_8859 to/afrom T.61 character set translation code is
+ * based on the code found in Enrique Silvestre Mora's iso-t61.c, found
+ * as part of this package:
+ *   ftp://pereiii.uji.es/pub/uji-ftp/unix/ldap/iso-t61.translation.tar.Z
+ * Enrique is now (10/95) at this address: enrique.silvestre@uv.es
+ *
+ * changes made by mcs@umich.edu 12 October 1995:
+ *   Change calling conventions of iso8859_t61() and t61_iso8859() to
+ *	match libldap conventions; rename to ldap_8859_to_t61() and
+ *	ldap_t61_to_8859().
+ *   Change conversion routines to deal with non-zero terminated strings.
+ *   ANSI-ize functions and include prototypes.
+ */
+
+/* iso-t61.c - ISO-T61 translation routines (version: 0.2.1, July-1994) */
+/*
+ * Copyright (c) 1994 Enrique Silvestre Mora, Universitat Jaume I, Spain.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the Universitat Jaume I. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Character set used: ISO 8859-1, ISO 8859-2, ISO 8859-3, ... */
+/* #define  ISO_8859      1 */
+
+#ifndef ISO_8859
+#  define ISO_8859     0
+#endif
+
+typedef unsigned char  Byte;
+typedef struct { Byte  a, b; } Couple;
+
+#ifdef NEEDPROTOS
+static Byte *c_to_hh( Byte *o, Byte c );
+static Byte *c_to_cc( Byte *o, Couple *cc, Byte c );
+static int hh_to_c( Byte *h );
+static Byte *cc_to_t61( Byte *o, Byte *s );
+#else /* NEEDPROTOS */
+static Byte *c_to_hh();
+static Byte *c_to_cc();
+static int hh_to_c();
+static Byte *cc_to_t61();
+#endif /* NEEDPROTOS */
+
+/*
+   Character choosed as base in diacritics alone: NO-BREAK SPACE.
+   (The standard say it must be a blank space, 0x20.)
+*/
+#define  ALONE  0xA0
+
+static Couple diacritic[16] = {
+#if (ISO_8859 == 1) || (ISO_8859 == 9)
+	{0,0},       {'`',0},     {0xb4,0},    {'^',0},
+	{'~',0},     {0xaf,0},    {'(',ALONE}, {'.',ALONE},
+	{0xa8,0},    {0,0},       {'0',ALONE}, {0xb8,0},
+	{0,0},       {'"',ALONE}, {';',ALONE}, {'<',ALONE},
+#elif (ISO_8859 == 2)
+	{0,0},       {'`',0},     {0xb4,0},    {'^',0},
+	{'~',0},     {'-',ALONE}, {0xa2,0},    {0xff,0},
+	{0xa8,0},    {0,0},       {'0',ALONE}, {0xb8,0},
+	{0,0},       {0xbd,0},    {0xb2,0},    {0xb7,0}
+#elif (ISO_8859 == 3)
+	{0,0},       {'`',0},     {0xb4,0},    {'^',0},
+	{'~',0},     {'-',ALONE}, {0xa2,0},    {0xff,0},
+	{0xa8,0},    {0,0},       {'0',ALONE}, {0xb8,0},
+	{0,0},       {'"',ALONE}, {';',ALONE}, {'<',ALONE}
+#elif (ISO_8859 == 4)
+	{0,0},       {'`',0},     {0xb4,0},    {'^',0},
+	{'~',0},     {0xaf,0},    {'(',ALONE}, {0xff,0},
+	{0xa8,0},    {0,0},       {'0',ALONE}, {0xb8,0},
+	{0,0},       {'"',ALONE}, {0xb2,0},    {0xb7,0}
+#else
+	{0,0},       {'`',0},     {'\'',ALONE}, {'^',0},
+	{'~',0},     {'-',ALONE}, {'(',ALONE},  {'.',ALONE},
+	{':',ALONE}, {0,0},       {'0',ALONE},  {',',ALONE},
+	{0,0},       {'"',ALONE}, {';',ALONE},  {'<',ALONE}
+#endif
+};
+
+/*
+   --- T.61 (T.51) letters with diacritics: conversion to ISO 8859-n -----
+       A,   C,   D,   E,   G,   H,   I,   J,   K,
+       L,   N,   O,   R,   S,   T,   U,   W,   Y,   Z.
+   -----------------------------------------------------------------------
+*/
+static int letter_w_diacritic[16][38] = {
+#if (ISO_8859 == 1)
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0xc0,0,   0,   0xc8,0,   0,   0xcc,0,   0,
+	0,   0,   0xd2,0,   0,   0,   0xd9,0,   0,   0,
+	0xe0,0,   0,   0xe8,0,   0,   0xec,0,   0,
+	0,   0,   0xf2,0,   0,   0,   0xf9,0,   0,   0,
+	0xc1,-1,  0,   0xc9,0,   0,   0xcd,0,   0,
+	-1,  -1,  0xd3,-1,  -1,  0,   0xda,0,   0xdd,-1,
+	0xe1,-1,  0,   0xe9,0,   0,   0xed,0,   0,
+	-1,  -1,  0xf3,-1,  -1,  0,   0xfa,0,   0xfd,-1,
+	0xc2,-1,  0,   0xca,-1,  -1,  0xce,-1,  0,
+	0,   0,   0xd4,0,   -1,  0,   0xdb,-1,  -1,  0,
+	0xe2,-1,  0,   0xea,-1,  -1,  0xee,-1,  0,
+	0,   0,   0xf4,0,   -1,  0,   0xfb,-1,  -1,  0,
+	0xc3,0,   0,   0,   0,   0,   -1,  0,   0,
+	0,   0xd1,0xd5,0,   0,   0,   -1,  0,   0,   0,
+	0xe3,0,   0,   0,   0,   0,   -1,  0,   0,
+	0,   0xf1,0xf5,0,   0,   0,   -1,  0,   0,   0,
+	-1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+	0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+	-1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+	0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+	-1,  0,   0,   0,   -1,  0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+	-1,  0,   0,   0,   -1,  0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+	0,   -1,  0,   -1,  -1,  0,   -1,  0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   -1,
+	0,   -1,  0,   -1,  -1,  0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   -1,
+	0xc4,0,   0,   0xcb,0,   0,   0xcf,0,   0,
+	0,   0,   0xd6,0,   0,   0,   0xdc,0,   -1,  0,
+	0xe4,0,   0,   0xeb,0,   0,   0xef,0,   0,
+	0,   0,   0xf6,0,   0,   0,   0xfc,0,   0xff,0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0xc5,0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+	0xe5,0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+	0,   0xc7,0,   0,   -1,  0,   0,   0,   -1,
+	-1,  -1,  0,   -1,  -1,  -1,  0,   0,   0,   0,
+	0,   0xe7,0,   0,   -1,  0,   0,   0,   -1,
+	-1,  -1,  0,   -1,  -1,  -1,  0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+	-1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+	0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+	-1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+	0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+	0,   -1,  -1,  -1,  0,   0,   0,   0,   0,
+	-1,  -1,  0,   -1,  -1,  -1,  0,   0,   0,   -1,
+	0,   -1,  -1,  -1,  0,   0,   0,   0,   0,
+	-1,  -1,  0,   -1,  -1,  -1,  0,   0,   0,   -1
+#elif (ISO_8859 == 2)
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	-1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+	0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+	-1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+	0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+	0xc1,0xc6,0,   0xc9,0,   0,   0xcd,0,   0,
+	0xc5,0xd1,0xd3,0xc0,0xa6,0,   0xda,0,   0xdd,0xac,
+	0xe1,0xe6,0,   0xe9,0,   0,   0xed,0,   0,
+	0xe5,0xf1,0xf3,0xe0,0xb6,0,   0xfa,0,   0xfd,0xbc,
+	0xc2,-1,  0,   -1,  -1,  -1,  0xce,-1,  0,
+	0,   0,   0xd4,0,   -1,  0,   -1,  -1,  -1,  0,
+	0xe2,-1,  0,   -1,  -1,  -1,  0xee,-1,  0,
+	0,   0,   0xf4,0,   -1,  0,   -1,  -1,  -1,  0,
+	-1,  0,   0,   0,   0,   0,   -1,  0,   0,
+	0,   -1,  -1,  0,   0,   0,   -1,  0,   0,   0,
+	-1,  0,   0,   0,   0,   0,   -1,  0,   0,
+	0,   -1,  -1,  0,   0,   0,   -1,  0,   0,   0,
+	-1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+	0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+	-1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+	0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+	0xc3,0,   0,   0,   -1,  0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+	0xe3,0,   0,   0,   -1,  0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+	0,   -1,  0,   -1,  -1,  0,   -1,  0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0xaf,
+	0,   -1,  0,   -1,  -1,  0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0xbf,
+	0xc4,0,   0,   0xcb,0,   0,   -1,  0,   0,
+	0,   0,   0xd6,0,   0,   0,   0xdc,0,   -1,  0,
+	0xe4,0,   0,   0xeb,0,   0,   -1,  0,   0,
+	0,   0,   0xf6,0,   0,   0,   0xfc,0,   -1,  0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	-1,  0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0xd9,0,   0,   0,
+	-1,  0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0xf9,0,   0,   0,
+	0,   0xc7,0,   0,   -1,  0,   0,   0,   -1,
+	-1,  -1,  0,   -1,  0xaa,0xde,0,   0,   0,   0,
+	0,   0xe7,0,   0,   -1,  0,   0,   0,   -1,
+	-1,  -1,  0,   -1,  0xba,0xfe,0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0xd5,0,   0,   0,   0xdb,0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0xf5,0,   0,   0,   0xfb,0,   0,   0,
+	0xa1,0,   0,   0xca,0,   0,   -1,  0,   0,
+	0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+	0xb1,0,   0,   0xea,0,   0,   -1,  0,   0,
+	0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+	0,   0xc8,0xcf,0xcc,0,   0,   0,   0,   0,
+	0xa5,0xd2,0,   0xd8,0xa9,0xab,0,   0,   0,   0xae,
+	0,   0xe8,0xef,0xec,0,   0,   0,   0,   0,
+	0xb5,0xf2,0,   0xf8,0xb9,0xbb,0,   0,   0,   0xbe
+#elif (ISO_8859 == 3)
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0xc0,0,   0,   0xc8,0,   0,   0xcc,0,   0,
+	0,   0,   0xd2,0,   0,   0,   0xd9,0,   0,   0,
+	0xe0,0,   0,   0xe8,0,   0,   0xec,0,   0,
+	0,   0,   0xf2,0,   0,   0,   0xf9,0,   0,   0,
+	0xc1,-1,  0,   0xc9,0,   0,   0xcd,0,   0,
+	-1,  -1,  0xd3,-1,  -1,  0,   0xda,0,   -1,  -1,
+	0xe1,-1,  0,   0xe9,0,   0,   0xed,0,   0,
+	-1,  -1,  0xf3,-1,  -1,  0,   0xfa,0,   -1,  -1,
+	0xc2,0xc6,0,   0xca,0xd8,0xa6,0xce,0xac,0,
+	0,   0,   0xd4,0,   0xde,0,   0xdb,-1,  -1,  0,
+	0xe2,0xe6,0,   0xea,0xf8,0xb6,0xee,0xbc,0,
+	0,   0,   0xf4,0,   0xfe,0,   0xfb,-1,  -1,  0,
+	-1,  0,   0,   0,   0,   0,   -1,  0,   0,
+	0,   0xd1,-1,  0,   0,   0,   -1,  0,   0,   0,
+	-1,  0,   0,   0,   0,   0,   -1,  0,   0,
+	0,   0xf1,-1,  0,   0,   0,   -1,  0,   0,   0,
+	-1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+	0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+	-1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+	0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+	-1,  0,   0,   0,   0xab,0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0xdd,0,   0,   0,
+	-1,  0,   0,   0,   0xbb,0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0xfd,0,   0,   0,
+	0,   0xc5,0,   -1,  0xd5,0,   0xa9,0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0xaf,
+	0,   0xe5,0,   -1,  0xf5,0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0xbf,
+	0xc4,0,   0,   0xcb,0,   0,   0xcf,0,   0,
+	0,   0,   0xd6,0,   0,   0,   0xdc,0,   -1,  0,
+	0xe4,0,   0,   0xeb,0,   0,   0xef,0,   0,
+	0,   0,   0xf6,0,   0,   0,   0xfc,0,   -1,  0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	-1,  0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+	-1,  0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+	0,   0xc7,0,   0,   -1,  0,   0,   0,   -1,
+	-1,  -1,  0,   -1,  0xaa,-1,  0,   0,   0,   0,
+	0,   0xe7,0,   0,   -1,  0,   0,   0,   -1,
+	-1,  -1,  0,   -1,  0xba,-1,  0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+	-1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+	0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+	-1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+	0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+	0,   -1,  -1,  -1,  0,   0,   0,   0,   0,
+	-1,  -1,  0,   -1,  -1,  -1,  0,   0,   0,   -1,
+	0,   -1,  -1,  -1,  0,   0,   0,   0,   0,
+	-1,  -1,  0,   -1,  -1,  -1,  0,   0,   0,   -1
+#elif (ISO_8859 == 4)
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	-1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+	0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+	-1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+	0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+	0xc1,-1,  0,   0xc9,0,   0,   0xcd,0,   0,
+	-1,  -1,  -1,  -1,  -1,  0,   0xda,0,   -1,  -1,
+	0xe1,-1,  0,   0xe9,0,   0,   0xed,0,   0,
+	-1,  -1,  -1,  -1,  -1,  0,   0xfa,0,   -1,  -1,
+	0xc2,-1,  0,   -1,  -1,  -1,  0xce,-1,  0,
+	0,   0,   0xd4,0,   -1,  0,   0xdb,-1,  -1,  0,
+	0xe2,-1,  0,   -1,  -1,  -1,  0xee,-1,  0,
+	0,   0,   0xf4,0,   -1,  0,   0xfb,-1,  -1,  0,
+	0xc3,0,   0,   0,   0,   0,   0xa5,0,   0,
+	0,   -1,  0xd5,0,   0,   0,   0xdd,0,   0,   0,
+	0xe3,0,   0,   0,   0,   0,   0xb5,0,   0,
+	0,   -1,  0xf5,0,   0,   0,   0xfd,0,   0,   0,
+	0xc0,0,   0,   0xaa,0,   0,   0xcf,0,   0,
+	0,   0,   0xd2,0,   0,   0,   0xde,0,   0,   0,
+	0xe0,0,   0,   0xba,0,   0,   0xef,0,   0,
+	0,   0,   0xf2,0,   0,   0,   0xfe,0,   0,   0,
+	-1,  0,   0,   0,   -1,  0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+	-1,  0,   0,   0,   -1,  0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+	0,   -1,  0,   0xcc,-1,  0,   -1,  0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   -1,
+	0,   -1,  0,   0xec,-1,  0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   -1,
+	0xc4,0,   0,   0xcb,0,   0,   -1,  0,   0,
+	0,   0,   0xd6,0,   0,   0,   0xdc,0,   -1,  0,
+	0xe4,0,   0,   0xeb,0,   0,   -1,  0,   0,
+	0,   0,   0xf6,0,   0,   0,   0xfc,0,   -1,  0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0xc5,0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+	0xe5,0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+	0,   -1,  0,   0,   0xab,0,   0,   0,   0xd3,
+	0xa6,0xd1,0,   0xa3,-1,  -1,  0,   0,   0,   0,
+	0,   -1,  0,   0,   0xbb,0,   0,   0,   0xf3,
+	0xb6,0xf1,0,   0xb3,-1,  -1,  0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+	0xa1,0,   0,   0xca,0,   0,   0xc7,0,   0,
+	0,   0,   0,   0,   0,   0,   0xd9,0,   0,   0,
+	0xb1,0,   0,   0xea,0,   0,   0xe7,0,   0,
+	0,   0,   0,   0,   0,   0,   0xf9,0,   0,   0,
+	0,   0xc8,-1,  -1,  0,   0,   0,   0,   0,
+	-1,  -1,  0,   -1,  0xa9,-1,  0,   0,   0,   0xae,
+	0,   0xe8,-1,  -1,  0,   0,   0,   0,   0,
+	-1,  -1,  0,   -1,  0xb9,-1,  0,   0,   0,   0xbe
+#elif (ISO_8859 == 9)
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0xc0,0,   0,   0xc8,0,   0,   0xcc,0,   0,
+	0,   0,   0xd2,0,   0,   0,   0xd9,0,   0,   0,
+	0xe0,0,   0,   0xe8,0,   0,   -1,  0,   0,
+	0,   0,   0xf2,0,   0,   0,   0xf9,0,   0,   0,
+	0xc1,-1,  0,   0xc9,0,   0,   0xcd,0,   0,
+	-1,  -1,  0xd3,-1,  -1,  0,   0xda,0,   -1,  -1,
+	0xe1,-1,  0,   0xe9,0,   0,   0xed,0,   0,
+	-1,  -1,  0xf3,-1,  -1,  0,   0xfa,0,   -1,  -1,
+	0xc2,-1,  0,   0xca,-1,  -1,  0xce,-1,  0,
+	0,   0,   0xd4,0,   -1,  0,   0xdb,-1,  -1,  0,
+	0xe2,-1,  0,   -1,  -1,  -1,  0xee,-1,  0,
+	0,   0,   0xf4,0,   -1,  0,   0xfb,-1,  -1,  0,
+	0xc3,0,   0,   0,   0,   0,   -1,  0,   0,
+	0,   0xd1,0xd5,0,   0,   0,   -1,  0,   0,   0,
+	0xe3,0,   0,   0,   0,   0,   -1,  0,   0,
+	0,   0xf1,0xf5,0,   0,   0,   -1,  0,   0,   0,
+	-1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+	0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+	-1,  0,   0,   -1,  0,   0,   0xef,0,   0,
+	0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+	-1,  0,   0,   0,   0xd0,0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+	-1,  0,   0,   0,   0xf0,0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+	0,   -1,  0,   -1,  -1,  0,   0xdd,0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   -1,
+	0,   -1,  0,   0xec,-1,  0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   -1,
+	0xc4,0,   0,   0xcb,0,   0,   0xcf,0,   0,
+	0,   0,   0xd6,0,   0,   0,   0xdc,0,   -1,  0,
+	0xe4,0,   0,   0xeb,0,   0,   -1,  0,   0,
+	0,   0,   0xf6,0,   0,   0,   0xfc,0,   0xff,0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0xc5,0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+	0xe5,0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+	0,   0xc7,0,   0,   -1,  0,   0,   0,   -1,
+	-1,  -1,  0,   -1,  0xde,-1,  0,   0,   0,   0,
+	0,   0xe7,0,   0,   -1,  0,   0,   0,   -1,
+	-1,  -1,  0,   -1,  0xfe,-1,  0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+	-1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+	0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+	-1,  0,   0,   0xea,0,   0,   -1,  0,   0,
+	0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+	0,   -1,  -1,  -1,  0,   0,   0,   0,   0,
+	-1,  -1,  0,   -1,  -1,  -1,  0,   0,   0,   -1,
+	0,   -1,  -1,  -1,  0,   0,   0,   0,   0,
+	-1,  -1,  0,   -1,  -1,  -1,  0,   0,   0,   -1
+#elif (ISO_8859 == 10)
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	-1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+	0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+	-1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+	0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+	0xc1,-1,  0,   0xc9,0,   0,   0xcd,0,   0,
+	-1,  -1,  0xd3,-1,  -1,  0,   0xda,0,   0xdd,-1,
+	0xe1,-1,  0,   0xe9,0,   0,   0xed,0,   0,
+	-1,  -1,  0xf3,-1,  -1,  0,   0xfa,0,   0xfd,-1,
+	0xc2,-1,  0,   -1,  -1,  -1,  0xce,-1,  0,
+	0,   0,   0xd4,0,   -1,  0,   0xdb,-1,  -1,  0,
+	0xe2,-1,  0,   -1,  -1,  -1,  0xee,-1,  0,
+	0,   0,   0xf4,0,   -1,  0,   0xfb,-1,  -1,  0,
+	0xc3,0,   0,   0,   0,   0,   0xa5,0,   0,
+	0,   -1,  0xd5,0,   0,   0,   0xd7,0,   0,   0,
+	0xe3,0,   0,   0,   0,   0,   0xb5,0,   0,
+	0,   -1,  0xf5,0,   0,   0,   0xf7,0,   0,   0,
+	0xc0,0,   0,   0xa2,0,   0,   0xa4,0,   0,
+	0,   0,   0xd2,0,   0,   0,   0xae,0,   0,   0,
+	0xe0,0,   0,   0xb2,0,   0,   0xb4,0,   0,
+	0,   0,   0xf2,0,   0,   0,   0xbe,0,   0,   0,
+	-1,  0,   0,   0,   -1,  0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+	-1,  0,   0,   0,   -1,  0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+	0,   -1,  0,   0xcc,-1,  0,   -1,  0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   -1,
+	0,   -1,  0,   0xec,-1,  0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   -1,
+	0xc4,0,   0,   0xcb,0,   0,   0xcf,0,   0,
+	0,   0,   0xd6,0,   0,   0,   0xdc,0,   -1,  0,
+	0xe4,0,   0,   0xeb,0,   0,   0xef,0,   0,
+	0,   0,   0xf6,0,   0,   0,   0xfc,0,   -1,  0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0xc5,0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+	0xe5,0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+	0,   -1,  0,   0,   0xa3,0,   0,   0,   0xa6,
+	0xa8,0xd1,0,   -1,  -1,  -1,  0,   0,   0,   0,
+	0,   -1,  0,   0,   0xb3,0,   0,   0,   0xb6,
+	0xb8,0xf1,0,   -1,  -1,  -1,  0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+	0xa1,0,   0,   0xca,0,   0,   0xc7,0,   0,
+	0,   0,   0,   0,   0,   0,   0xd9,0,   0,   0,
+	0xb1,0,   0,   0xea,0,   0,   0xe7,0,   0,
+	0,   0,   0,   0,   0,   0,   0xf9,0,   0,   0,
+	0,   0xc8,-1,  -1,  0,   0,   0,   0,   0,
+	-1,  -1,  0,   -1,  0xaa,-1,  0,   0,   0,   0xac,
+	0,   0xe8,-1,  -1,  0,   0,   0,   0,   0,
+	-1,  -1,  0,   -1,  0xba,-1,  0,   0,   0,   0xbc
+#else
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	-1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+	0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+	-1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+	0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+	-1,  -1,  0,   -1,  0,   0,   -1,  0,   0,
+	-1,  -1,  -1,  -1,  -1,  0,   -1,  0,   -1,  -1,
+	-1,  -1,  0,   -1,  0,   0,   -1,  0,   0,
+	-1,  -1,  -1,  -1,  -1,  0,   -1,  0,   -1,  -1,
+	-1,  -1,  0,   -1,  -1,  -1,  -1,  -1,  0,
+	0,   0,   -1,  0,   -1,  0,   -1,  -1,  -1,  0,
+	-1,  -1,  0,   -1,  -1,  -1,  -1,  -1,  0,
+	0,   0,   -1,  0,   -1,  0,   -1,  -1,  -1,  0,
+	-1,  0,   0,   0,   0,   0,   -1,  0,   0,
+	0,   -1,  -1,  0,   0,   0,   -1,  0,   0,   0,
+	-1,  0,   0,   0,   0,   0,   -1,  0,   0,
+	0,   -1,  -1,  0,   0,   0,   -1,  0,   0,   0,
+	-1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+	0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+	-1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+	0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+	-1,  0,   0,   0,   -1,  0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+	-1,  0,   0,   0,   -1,  0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+	0,   -1,  0,   -1,  -1,  0,   -1,  0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   -1,
+	0,   -1,  0,   -1,  -1,  0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   -1,
+	-1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+	0,   0,   -1,  0,   0,   0,   -1,  0,   -1,  0,
+	-1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+	0,   0,   -1,  0,   0,   0,   -1,  0,   -1,  0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	-1,  0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+	-1,  0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+	0,   -1,  0,   0,   -1,  0,   0,   0,   -1,
+	-1,  -1,  0,   -1,  -1,  -1,  0,   0,   0,   0,
+	0,   -1,  0,   0,   -1,  0,   0,   0,   -1,
+	-1,  -1,  0,   -1,  -1,  -1,  0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+	0,   0,   0,   0,   0,   0,   0,   0,   0,
+	0,   0,   -1,  0,   0,   0,   -1,  0,   0,   0,
+	-1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+	0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+	-1,  0,   0,   -1,  0,   0,   -1,  0,   0,
+	0,   0,   0,   0,   0,   0,   -1,  0,   0,   0,
+	0,   -1,  -1,  -1,  0,   0,   0,   0,   0,
+	-1,  -1,  0,   -1,  -1,  -1,  0,   0,   0,   -1,
+	0,   -1,  -1,  -1,  0,   0,   0,   0,   0,
+	-1,  -1,  0,   -1,  -1,  -1,  0,   0,   0,   -1
+#endif
+};
+
+/*
+--- T.61 characters [0xA0 .. 0xBF] -----------------
+*/
+static Couple trans_t61a_iso8859[32] = {
+#if (ISO_8859 == 1) || (ISO_8859 == 9)
+	{'N','S'}, {0xa1,0},  {0xa2,0},  {0xa3,0},
+	{'D','O'}, {0xa5,0},  {'C','u'}, {0xa7,0},
+	{0xa4,0},  {'\'','6'},{'"','6'}, {0xab,0},
+	{'<','-'}, {'-','!'}, {'-','>'}, {'-','v'},
+	{0xb0,0},  {0xb1,0},  {0xb2,0},  {0xb3,0},
+	{0xd7,0},  {0xb5,0},  {0xb6,0},  {0xb7,0},
+	{0xf7,0},  {'\'','9'},{'"','9'}, {0xbb,0},
+	{0xbc,0},  {0xbd,0},  {0xbe,0},  {0xbf,0}
+#elif (ISO_8859 == 2) || (ISO_8859 == 4)
+	{'N','S'}, {'!','I'}, {'C','t'}, {'P','d'},
+	{'D','O'}, {'Y','e'}, {'C','u'}, {0xa7,0},
+	{0xa4,0},  {'\'','6'},{'"','6'}, {'<','<'},
+	{'<','-'}, {'-','!'}, {'-','>'}, {'-','v'},
+	{0xb0,0},  {'+','-'}, {'2','S'}, {'3','S'},
+	{0xd7,0},  {'M','y'}, {'P','I'}, {'.','M'},
+	{0xf7,0},  {'\'','9'},{'"','9'}, {'>','>'},
+	{'1','4'}, {'1','2'}, {'3','4'}, {'?','I'},
+#elif (ISO_8859 == 3)
+	{'N','S'}, {'!','I'}, {'C','t'}, {0xa3,0},
+	{'D','O'}, {'Y','e'}, {'C','u'}, {0xa7,0},
+	{0xa4,0},  {'\'','6'},{'"','6'}, {'<','<'},
+	{'<','-'}, {'-','!'}, {'-','>'}, {'-','v'},
+	{0xb0,0},  {'+','-'}, {0xb2,0},  {0xb3,0},
+	{0xd7,0},  {0xb5,0},  {'P','I'}, {0xb7,0},
+	{0xf7,0},  {'\'','9'},{'"','9'}, {'>','>'},
+	{'1','4'}, {0xbd,0},  {'3','4'}, {'?','I'}
+#elif (ISO_8859 == 10)
+	{'N','S'}, {'!','I'}, {'C','t'}, {'P','d'},
+	{'D','O'}, {'Y','e'}, {'C','u'}, {0xa7,0},
+	{'C','u'}, {'\'','6'},{'"','6'}, {'<','<'},
+	{'<','-'}, {'-','!'}, {'-','>'}, {'-','v'},
+	{0xb0,0},  {'+','-'}, {'2','S'}, {'3','S'},
+	{'*','X'}, {'M','y'}, {'P','I'}, {0xb7,0},
+	{'-',':'}, {'\'','9'},{'"','9'}, {'>','>'},
+	{'1','4'}, {'1','2'}, {'3','4'}, {'?','I'}
+#else
+	{'N','S'}, {'!','I'}, {'C','t'}, {'P','d'},
+	{'D','O'}, {'Y','e'}, {'C','u'}, {'S','E'},
+	{'X','O'}, {'\'','6'},{'"','6'}, {'<','<'},
+	{'<','-'}, {'-','!'}, {'-','>'}, {'-','v'},
+	{'D','G'}, {'+','-'}, {'2','S'}, {'3','S'},
+	{'*','X'}, {'M','y'}, {'P','I'}, {'.','M'},
+	{'-',':'}, {'\'','9'},{'"','9'}, {'>','>'},
+	{'1','4'}, {'1','2'}, {'3','4'}, {'?','I'}
+#endif
+};
+
+/*
+--- T.61 characters [0xE0 .. 0xFF] -----------------
+*/
+static Couple trans_t61b_iso8859[48] = {
+#if (ISO_8859 == 1)
+	{'-','M'}, {0xb9,0},  {0xae,0},  {0xa9,0},
+	{'T','M'}, {'M','8'}, {0xac,0},  {0xa6,0},
+	{0,0},     {0,0},     {0,0},     {0,0},
+	{'1','8'}, {'3','8'}, {'5','8'}, {'7','8'},
+	{'O','m'}, {0xc6,0},  {0xd0,0},  {0xaa,0},
+	{'H','/'}, {0,0},     {'I','J'}, {'L','.'},
+	{'L','/'}, {0xd8,0},  {'O','E'}, {0xba,0},
+	{0xde,0},  {'T','/'}, {'N','G'}, {'\'','n'},
+	{'k','k'}, {0xe6,0},  {'d','/'}, {0xf0,0},
+	{'h','/'}, {'i','.'}, {'i','j'}, {'l','.'},
+	{'l','/'}, {0xf8,0},  {'o','e'}, {0xdf,0},
+	{0xfe,0},  {'t','/'}, {'n','g'}, {'-','-'}
+#elif (ISO_8859 == 2)
+	{'-','M'}, {'1','S'}, {'R','g'}, {'C','o'},
+	{'T','M'}, {'M','8'}, {'N','O'}, {'B','B'},
+	{0,0},     {0,0},     {0,0},     {0,0},
+	{'1','8'}, {'3','8'}, {'5','8'}, {'7','8'},
+	{'O','m'}, {'A','E'}, {0xd0,0},  {'-','a'},
+	{'H','/'}, {0,0},     {'I','J'}, {'L','.'},
+	{0xa3,0},  {'O','/'}, {'O','E'}, {'-','o'},
+	{'T','H'}, {'T','/'}, {'N','G'}, {'\'','n'},
+	{'k','k'}, {'a','e'}, {0xf0,0},  {'d','-'},
+	{'h','/'}, {'i','.'}, {'i','j'}, {'l','.'},
+	{0xb3,0},  {'o','/'}, {'o','e'}, {0xdf,0},
+	{'t','h'}, {'t','/'}, {'n','g'}, {'-','-'}
+#elif (ISO_8859 == 3)
+	{'-','M'}, {'1','S'}, {'R','g'}, {'C','o'},
+	{'T','M'}, {'M','8'}, {'N','O'}, {'B','B'},
+	{0,0},     {0,0},     {0,0},     {0,0},
+	{'1','8'}, {'3','8'}, {'5','8'}, {'7','8'},
+	{'O','m'}, {'A','E'}, {'D','/'}, {'-','a'},
+	{0xa1,0},  {0,0},     {'I','J'}, {'L','.'},
+	{'L','/'}, {'O','/'}, {'O','E'}, {'-','o'},
+	{'T','H'}, {'T','/'}, {'N','G'}, {'\'','n'},
+	{'k','k'}, {'a','e'}, {'d','/'}, {'d','-'},
+	{0xb1,0},  {0xb9,0},  {'i','j'}, {'l','.'},
+	{'l','/'}, {'o','/'}, {'o','e'}, {0xdf,0},
+	{'t','h'}, {'t','/'}, {'n','g'}, {'-','-'}
+#elif (ISO_8859 == 4)
+	{'-','M'}, {'1','S'}, {'R','g'}, {'C','o'},
+	{'T','M'}, {'M','8'}, {'N','O'}, {'B','B'},
+	{0,0},     {0,0},     {0,0},     {0,0},
+	{'1','8'}, {'3','8'}, {'5','8'}, {'7','8'},
+	{'O','m'}, {0xc6,0},  {0xd0,0},  {'-','a'},
+	{'H','/'}, {0,0},     {'I','J'}, {'L','.'},
+	{'L','/'}, {0xd8,0},  {'O','E'}, {'-','o'},
+	{'T','H'}, {0xac,0},  {0xbd,0},  {'\'','n'},
+	{0xa2,0},  {0xe6,0},  {0xf0,0},  {'d','-'},
+	{'h','/'}, {'i','.'}, {'i','j'}, {'l','.'},
+	{'l','/'}, {0xf8,0},  {'o','e'}, {0xdf,0},
+	{'t','h'}, {0xbc,0},  {0xbf,0},  {'-','-'}
+#elif (ISO_8859 == 9)
+	{'-','M'}, {0xb9,0},  {0xae,0},  {0xa9,0},
+	{'T','M'}, {'M','8'}, {0xac,0},  {0xa6,0},
+	{0,0},     {0,0},     {0,0},     {0,0},
+	{'1','8'}, {'3','8'}, {'5','8'}, {'7','8'},
+	{'O','m'}, {0xc6,0},  {'D','/'}, {0xaa,0},
+	{'H','/'}, {0,0},     {'I','J'}, {'L','.'},
+	{'L','/'}, {0xd8,0},  {'O','E'}, {0xba,0},
+	{'T','H'}, {'T','/'}, {'N','G'}, {'\'','n'},
+	{'k','k'}, {0xe6,0},  {'d','/'}, {'d','-'},
+	{'h','/'}, {0xfd,0},  {'i','j'}, {'l','.'},
+	{'l','/'}, {0xf8,0},  {'o','e'}, {0xdf,0},
+	{'t','h'}, {'t','/'}, {'n','g'}, {'-','-'}
+#elif (ISO_8859 == 10)
+	{0xbd,0},  {'1','S'}, {'R','g'}, {'C','o'},
+	{'T','M'}, {'M','8'}, {'N','O'}, {'B','B'},
+	{0,0},     {0,0},     {0,0},     {0,0},
+	{'1','8'}, {'3','8'}, {'5','8'}, {'7','8'},
+	{'O','m'}, {0xc6,0},  {0xa9,0},  {'-','a'},
+	{'H','/'}, {0,0},     {'I','J'}, {'L','.'},
+	{'L','/'}, {0xd8,0},  {'O','E'}, {'-','o'},
+	{0xde,0},  {0xab,0},  {0xaf,0},  {'\'','n'},
+	{0xff,0},  {0xe6,0},  {0xb9,0},  {0xf0,0},
+	{'h','/'}, {'i','.'}, {'i','j'}, {'l','.'},
+	{'l','/'}, {0xf8,0},  {'o','e'}, {0xdf,0},
+	{0xfe,0},  {0xbb,0},  {0xbf,0},  {'-','-'}
+#else
+	{'-','M'}, {'1','S'}, {'R','g'}, {'C','o'},
+	{'T','M'}, {'M','8'}, {'N','O'}, {'B','B'},
+	{0,0},     {0,0},     {0,0},     {0,0},
+	{'1','8'}, {'3','8'}, {'5','8'}, {'7','8'},
+	{'O','m'}, {'A','E'}, {'D','/'}, {'-','a'},
+	{'H','/'}, {0,0},     {'I','J'}, {'L','.'},
+	{'L','/'}, {'O','/'}, {'O','E'}, {'-','o'},
+	{'T','H'}, {'T','/'}, {'N','G'}, {'\'','n'},
+	{'k','k'}, {'a','e'}, {'d','/'}, {'d','-'},
+	{'h','/'}, {'i','.'}, {'i','j'}, {'l','.'},
+	{'l','/'}, {'o','/'}, {'o','e'}, {'s','s'},
+	{'t','h'}, {'t','-'}, {'n','g'}, {'-','-'}
+#endif
+};
+
+/*
+--- ISO 8859-n characters <0xA0 .. 0xFF> -------------------
+*/
+#if (ISO_8859 == 1)
+static Couple trans_iso8859_t61[96] = {
+	{0xa0,0},     {0xa1,0},     {0xa2,0},     {0xa3,0},
+	{0xa8,0},     {0xa5,0},     {0xd7,0},     {0xa7,0},
+	{0xc8,ALONE}, {0xd3,0},     {0xe3,0},     {0xab,0},
+	{0xd6,0},     {0xff,0},     {0xd2,0},     {0xc5,ALONE},
+	{0xb0,0},     {0xb1,0},     {0xb2,0},     {0xb3,0},
+	{0xc2,ALONE}, {0xb5,0},     {0xb6,0},     {0xb7,0},
+	{0xcb,ALONE}, {0xd1,0},     {0xeb,0},     {0xbb,0},
+	{0xbc,0},     {0xbd,0},     {0xbe,0},     {0xbf,0},
+	{0xc1,'A'},   {0xc2,'A'},   {0xc3,'A'},   {0xc4,'A'},
+	{0xc8,'A'},   {0xca,'A'},   {0xe1,0},     {0xcb,'C'},
+	{0xc1,'E'},   {0xc2,'E'},   {0xc3,'E'},   {0xc8,'E'},
+	{0xc1,'I'},   {0xc2,'I'},   {0xc3,'I'},   {0xc8,'I'},
+	{0xe2,0},     {0xc4,'N'},   {0xc1,'O'},   {0xc2,'O'},
+	{0xc3,'O'},   {0xc4,'O'},   {0xc8,'O'},   {0xb4,0},
+	{0xe9,0},     {0xc1,'U'},   {0xc2,'U'},   {0xc3,'U'},
+	{0xc8,'U'},   {0xc2,'Y'},   {0xec,0},     {0xfb,0},
+	{0xc1,'a'},   {0xc2,'a'},   {0xc3,'a'},   {0xc4,'a'},
+	{0xc8,'a'},   {0xca,'a'},   {0xf1,0},     {0xcb,'c'},
+	{0xc1,'e'},   {0xc2,'e'},   {0xc3,'e'},   {0xc8,'e'},
+	{0xc1,'i'},   {0xc2,'i'},   {0xc3,'i'},   {0xc8,'i'},
+	{0xf3,0},     {0xc4,'n'},   {0xc1,'o'},   {0xc2,'o'},
+	{0xc3,'o'},   {0xc4,'o'},   {0xc8,'o'},   {0xb8,0},
+	{0xf9,0},     {0xc1,'u'},   {0xc2,'u'},   {0xc3,'u'},
+	{0xc8,'u'},   {0xc2,'y'},   {0xfc,0},     {0xc8,'y'}
+};
+#elif (ISO_8859 == 2)
+static Couple trans_iso8859_t61[96] = {
+	{0xa0,0},     {0xce,'A'},   {0xc6,ALONE}, {0xe8,0},
+	{0xa8,0},     {0xcf,'L'},   {0xc2,'S'},   {0xa7,0},
+	{0xc8,ALONE}, {0xcf,'S'},   {0xcb,'S'},   {0xcf,'T'},
+	{0xc2,'Z'},   {0xff,0},     {0xcf,'Z'},   {0xc7,'Z'},
+	{0xb0,0},     {0xce,'a'},   {0xce,ALONE}, {0xf8,0},
+	{0xc2,ALONE}, {0xcf,'l'},   {0xc2,'s'},   {0xcf,ALONE},
+	{0xcb,ALONE}, {0xcf,'s'},   {0xcb,'s'},   {0xcf,'t'},
+	{0xc2,'z'},   {0xcd,ALONE}, {0xcf,'z'},   {0xc7,'z'},
+	{0xc2,'R'},   {0xc2,'A'},   {0xc3,'A'},   {0xc6,'A'},
+	{0xc8,'A'},   {0xc2,'L'},   {0xc2,'C'},   {0xcb,'C'},
+	{0xcf,'C'},   {0xc2,'E'},   {0xce,'E'},   {0xc8,'E'},
+	{0xcf,'E'},   {0xc2,'I'},   {0xc3,'I'},   {0xcf,'D'},
+	{0xe2,0},     {0xc2,'N'},   {0xcf,'N'},   {0xc2,'O'},
+	{0xc3,'O'},   {0xcd,'O'},   {0xc8,'O'},   {0xb4,0},
+	{0xcf,'R'},   {0xca,'U'},   {0xc2,'U'},   {0xcd,'U'},
+	{0xc8,'U'},   {0xc2,'Y'},   {0xcb,'T'},   {0xfb,0},
+	{0xc2,'r'},   {0xc2,'a'},   {0xc3,'a'},   {0xc6,'a'},
+	{0xc8,'a'},   {0xc2,'l'},   {0xc2,'c'},   {0xcb,'c'},
+	{0xcf,'c'},   {0xc2,'e'},   {0xce,'e'},   {0xc8,'e'},
+	{0xcf,'e'},   {0xc2,'i'},   {0xc3,'i'},   {0xcf,'d'},
+	{0xf2,0},     {0xc2,'n'},   {0xcf,'n'},   {0xc2,'o'},
+	{0xc3,'o'},   {0xcd,'o'},   {0xc8,'o'},   {0xb8,0},
+	{0xcf,'r'},   {0xca,'u'},   {0xc2,'u'},   {0xcd,'u'},
+	{0xc8,'u'},   {0xc2,'y'},   {0xcb,'t'},   {0xc7,ALONE}
+};
+#elif (ISO_8859 == 3)
+static Couple trans_iso8859_t61[96] = {
+	{0xa0,0},     {0xe4,0},     {0xc6,ALONE}, {0xa3,0},
+	{0xa8,0},     {0,0},        {0xc3,'H'},   {0xa7,0},
+	{0xc8,ALONE}, {0xc7,'I'},   {0xcb,'S'},   {0xc6,'G'},
+	{0xc3,'J'},   {0xff,0},     {0,0},        {0xc7,'Z'},
+	{0xb0,0},     {0xf4,0},     {0xb2,0},     {0xb3,0},
+	{0xc2,ALONE}, {0xb5,0},     {0xc3,'h'},   {0xb7,0},
+	{0xcb,ALONE}, {0xf5,0},     {0xcb,'s'},   {0xc6,'g'},
+	{0xc3,'j'},   {0xbd,0},     {0,0},        {0xc7,'z'},
+	{0xc1,'A'},   {0xc2,'A'},   {0xc3,'A'},   {0,0},
+	{0xc8,'A'},   {0xc7,'C'},   {0xc3,'C'},   {0xcb,'C'},
+	{0xc1,'E'},   {0xc2,'E'},   {0xc3,'E'},   {0xc8,'E'},
+	{0xc1,'I'},   {0xc2,'I'},   {0xc3,'I'},   {0xc8,'I'},
+	{0,0},        {0xc4,'N'},   {0xc1,'O'},   {0xc2,'O'},
+	{0xc3,'O'},   {0xc7,'G'},   {0xc8,'O'},   {0xb4,0},
+	{0xc3,'G'},   {0xc1,'U'},   {0xc2,'U'},   {0xc3,'U'},
+	{0xc8,'U'},   {0xc6,'U'},   {0xc3,'S'},   {0xfb,0},
+	{0xc1,'a'},   {0xc2,'a'},   {0xc3,'a'},   {0,0},
+	{0xc8,'a'},   {0xc7,'c'},   {0xc3,'c'},   {0xcb,'c'},
+	{0xc1,'e'},   {0xc2,'e'},   {0xc3,'e'},   {0xc8,'e'},
+	{0xc1,'i'},   {0xc2,'i'},   {0xc3,'i'},   {0xc8,'i'},
+	{0,0},        {0xc4,'n'},   {0xc1,'o'},   {0xc2,'o'},
+	{0xc3,'o'},   {0xc7,'g'},   {0xc8,'o'},   {0xb8,0},
+	{0xc3,'g'},   {0xc1,'u'},   {0xc2,'u'},   {0xc3,'u'},
+	{0xc8,'u'},   {0xc6,'u'},   {0xc3,'s'},   {0xc7,ALONE}
+};
+#elif (ISO_8859 == 4)
+static Couple trans_iso8859_t61[96] = {
+	{0xa0,0},     {0xce,'A'},   {0xf0,0},     {0xcb,'R'},
+	{0xa8,0},     {0xc4,'I'},   {0xcb,'L'},   {0xa7,0},
+	{0xc8,ALONE}, {0xcf,'S'},   {0xc5,'E'},   {0xcb,'G'},
+	{0xed,0},     {0xff,0},     {0xcf,'Z'},   {0xc5,ALONE},
+	{0xb0,0},     {0xce,'a'},   {0xce,ALONE}, {0xcb,'r'},
+	{0xc2,ALONE}, {0xc4,'i'},   {0xcb,'l'},   {0xcf,ALONE},
+	{0xcb,ALONE}, {0xcf,'s'},   {0xc5,'e'},   {0xcb,'g'},
+	{0xfd,0},     {0xee,0},     {0xcf,'z'},   {0xfe,0},
+	{0xc5,'A'},   {0xc2,'A'},   {0xc3,'A'},   {0xc4,'A'},
+	{0xc8,'A'},   {0xca,'A'},   {0xe1,0},     {0xce,'I'},
+	{0xcf,'C'},   {0xc2,'E'},   {0xce,'E'},   {0xc8,'E'},
+	{0xc7,'E'},   {0xc2,'I'},   {0xc3,'I'},   {0xc5,'I'},
+	{0xe2,0},     {0xcb,'N'},   {0xc5,'O'},   {0xcb,'K'},
+	{0xc3,'O'},   {0xc4,'O'},   {0xc8,'O'},   {0xb4,0},
+	{0xe9,0},     {0xce,'U'},   {0xc2,'U'},   {0xc3,'U'},
+	{0xc8,'U'},   {0xc4,'U'},   {0xc5,'U'},   {0xfb,0},
+	{0xc5,'a'},   {0xc2,'a'},   {0xc3,'a'},   {0xc4,'a'},
+	{0xc8,'a'},   {0xca,'a'},   {0xf1,0},     {0xce,'i'},
+	{0xcf,'c'},   {0xc2,'e'},   {0xce,'e'},   {0xc8,'e'},
+	{0xc7,'e'},   {0xc2,'i'},   {0xc3,'i'},   {0xc5,'i'},
+	{0xf2,0},     {0xcb,'n'},   {0xc5,'o'},   {0xcb,'k'},
+	{0xc3,'o'},   {0xc4,'o'},   {0xc8,'o'},   {0xb8,0},
+	{0xf9,0},     {0xce,'u'},   {0xc2,'u'},   {0xc3,'u'},
+	{0xc8,'u'},   {0xc4,'u'},   {0xc5,'u'},   {0xc7,ALONE}
+};
+#elif (ISO_8859 == 9)
+static Couple trans_iso8859_t61[96] = {
+	{0xa0,0},     {0xa1,0},     {0xa2,0},     {0xa3,0},
+	{0xa8,0},     {0xa5,0},     {0xd7,0},     {0xa7,0},
+	{0xc8,ALONE}, {0xd3,0},     {0xe3,0},     {0xab,0},
+	{0xd6,0},     {0xff,0},     {0xd2,0},     {0xc5,ALONE},
+	{0xb0,0},     {0xb1,0},     {0xb2,0},     {0xb3,0},
+	{0xc2,ALONE}, {0xb5,0},     {0xb6,0},     {0xb7,0},
+	{0xcb,ALONE}, {0xd1,0},     {0xeb,0},     {0xbb,0},
+	{0xbc,0},     {0xbd,0},     {0xbe,0},     {0xbf,0},
+	{0xc1,'A'},   {0xc2,'A'},   {0xc3,'A'},   {0xc4,'A'},
+	{0xc8,'A'},   {0xca,'A'},   {0xe1,0},     {0xcb,'C'},
+	{0xc1,'E'},   {0xc2,'E'},   {0xc3,'E'},   {0xc8,'E'},
+	{0xc1,'I'},   {0xc2,'I'},   {0xc3,'I'},   {0xc8,'I'},
+	{0xc6,'G'},   {0xc4,'N'},   {0xc1,'O'},   {0xc2,'O'},
+	{0xc3,'O'},   {0xc4,'O'},   {0xc8,'O'},   {0xb4,0},
+	{0xe9,0},     {0xc1,'U'},   {0xc2,'U'},   {0xc3,'U'},
+	{0xc8,'U'},   {0xc7,'I'},   {0xcb,'S'},   {0xfb,0},
+	{0xc1,'a'},   {0xc2,'a'},   {0xc3,'a'},   {0xc4,'a'},
+	{0xc8,'a'},   {0xca,'a'},   {0xf1,0},     {0xcb,'c'},
+	{0xc1,'e'},   {0xc2,'e'},   {0xce,'e'},   {0xc8,'e'},
+	{0xc7,'e'},   {0xc2,'i'},   {0xc3,'i'},   {0xc5,'i'},
+	{0xc6,'g'},   {0xc4,'n'},   {0xc1,'o'},   {0xc2,'o'},
+	{0xc3,'o'},   {0xc4,'o'},   {0xc8,'o'},   {0xb8,0},
+	{0xf9,0},     {0xc1,'u'},   {0xc2,'u'},   {0xc3,'u'},
+	{0xc8,'u'},   {0xf5,0},     {0xcb,'s'},   {0xc8,'y'}
+};
+#elif (ISO_8859 == 10)
+static Couple trans_iso8859_t61[96] = {
+	{0xa0,0},     {0xce,'A'},   {0xc5,'E'},   {0xcb,'G'},
+	{0xc5,'I'},   {0xc4,'I'},   {0xcb,'K'},   {0xa7,0},
+	{0xcb,'L'},   {0xe2,0},     {0xcf,'S'},   {0xed,0},
+	{0xcf,'Z'},   {0xff,0},     {0xc5,'U'},   {0xee,0},
+	{0xb0,0},     {0xce,'a'},   {0xc5,'e'},   {0xcb,'g'},
+	{0xc5,'i'},   {0xc4,'i'},   {0xcb,'k'},   {0xb7,0},
+	{0xcb,'l'},   {0xf2,0},     {0xcf,'s'},   {0xfd,0},
+	{0xcf,'z'},   {0xd0,0},     {0xc5,'u'},   {0xfe,0},
+	{0xc5,'A'},   {0xc2,'A'},   {0xc3,'A'},   {0xc4,'A'},
+	{0xc8,'A'},   {0xca,'A'},   {0xe1,0},     {0xce,'I'},
+	{0xcf,'C'},   {0xc2,'E'},   {0xce,'E'},   {0xc8,'E'},
+	{0xc7,'E'},   {0xc2,'I'},   {0xc3,'I'},   {0xc8,'I'},
+	{0,0},        {0xcb,'N'},   {0xc5,'O'},   {0xc2,'O'},
+	{0xc3,'O'},   {0xc4,'O'},   {0xc8,'O'},   {0xc4,'U'},
+	{0xe9,0},     {0xce,'U'},   {0xc2,'U'},   {0xc3,'U'},
+	{0xc8,'U'},   {0xc2,'Y'},   {0xec,0},     {0xfb,0},
+	{0xc5,'a'},   {0xc2,'a'},   {0xc3,'a'},   {0xc4,'a'},
+	{0xc8,'a'},   {0xca,'a'},   {0xf1,0},     {0xce,'i'},
+	{0xcf,'c'},   {0xc2,'e'},   {0xce,'e'},   {0xc8,'e'},
+	{0xc7,'e'},   {0xc2,'i'},   {0xc3,'i'},   {0xc8,'i'},
+	{0xf3,0},     {0xcb,'n'},   {0xc5,'o'},   {0xc2,'o'},
+	{0xc3,'o'},   {0xc4,'o'},   {0xc8,'o'},   {0xc4,'u'},
+	{0xf9,0},     {0xce,'u'},   {0xc2,'u'},   {0xc3,'u'},
+	{0xc8,'u'},   {0xc2,'y'},   {0xfc,0},     {0xf0,0}
+};
+#endif
+
+
+static Byte *
+c_to_hh( Byte *o, Byte c )
+{
+  Byte n;
+
+  *o++ = '{'; *o++ = 'x';
+  n = c >> 4;
+  *o++ = ((n < 0xA) ? '0' : 'A' - 0xA) + n;
+  n = c & 0x0F;
+  *o++ = ((n < 0xA) ? '0' : 'A' - 0xA) + n;
+  *o++ = '}';
+  return o;
+}
+
+
+static Byte *
+c_to_cc( Byte *o, Couple *cc, Byte c )
+{
+  if ( (*cc).a != 0 ) {
+    if ( (*cc).b == 0 )
+      *o++ = (*cc).a;
+    else {
+      *o++ = '{';
+      *o++ = (*cc).a;
+      *o++ = (*cc).b;
+      *o++ = '}';
+    }
+    return o;
+  }
+  else
+    return c_to_hh( o, c );
+}
+
+/* --- routine to convert from T.61 to ISO 8859-n --- */
+
+int
+ldap_t61_to_8859( char **bufp, unsigned long *buflenp, int free_input )
+{
+  Byte		*s, *oo, *o;
+  unsigned int  n;
+  int           c;
+  unsigned long len;
+  Couple        *cc;
+
+  LDAPDebug( LDAP_DEBUG_TRACE, "ldap_t61_to_8859 input length: %ld\n",
+	*buflenp, 0, 0 );
+
+  len = *buflenp;
+  s = (Byte *) *bufp;
+
+  if ( (o = oo = (Byte *)NSLDAPI_MALLOC( 2 * len + 64 )) == NULL ) {
+        return( 1 );
+  }
+
+  while ( (char *)s - *(char **)bufp < len ) {
+    switch ( *s >> 4 ) {
+
+    case 0xA: case 0xB:
+      o = c_to_cc( o, &trans_t61a_iso8859[ *s - 0xA0 ], *s );
+      s++;
+      break;
+
+    case 0xD: case 0xE: case 0xF:
+      o = c_to_cc( o, &trans_t61b_iso8859[ *s - 0xD0 ], *s );
+      s++;
+      break;
+
+    case 0xC:
+      if ( (*s == 0xC0) || (*s == 0xC9) || (*s == 0xCC) ) {
+        o = c_to_hh( o, *s++ );
+        break;
+      }
+
+      n = (*s++) - 0xC0;
+      switch ( *s ) {
+
+      case 'A':  c = letter_w_diacritic[n][0]; break;
+      case 'C':  c = letter_w_diacritic[n][1]; break;
+      case 'D':  c = letter_w_diacritic[n][2]; break;
+      case 'E':  c = letter_w_diacritic[n][3]; break;
+      case 'G':  c = letter_w_diacritic[n][4]; break;
+      case 'H':  c = letter_w_diacritic[n][5]; break;
+      case 'I':  c = letter_w_diacritic[n][6]; break;
+      case 'J':  c = letter_w_diacritic[n][7]; break;
+      case 'K':  c = letter_w_diacritic[n][8]; break;
+      case 'L':  c = letter_w_diacritic[n][9]; break;
+      case 'N':  c = letter_w_diacritic[n][10]; break;
+      case 'O':  c = letter_w_diacritic[n][11]; break;
+      case 'R':  c = letter_w_diacritic[n][12]; break;
+      case 'S':  c = letter_w_diacritic[n][13]; break;
+      case 'T':  c = letter_w_diacritic[n][14]; break;
+      case 'U':  c = letter_w_diacritic[n][15]; break;
+      case 'W':  c = letter_w_diacritic[n][16]; break;
+      case 'Y':  c = letter_w_diacritic[n][17]; break;
+      case 'Z':  c = letter_w_diacritic[n][18]; break;
+
+      case 'a':  c = letter_w_diacritic[n][19]; break;
+      case 'c':  c = letter_w_diacritic[n][20]; break;
+      case 'd':  c = letter_w_diacritic[n][21]; break;
+      case 'e':  c = letter_w_diacritic[n][22]; break;
+      case 'g':  c = letter_w_diacritic[n][23]; break;
+      case 'h':  c = letter_w_diacritic[n][24]; break;
+      case 'i':  c = letter_w_diacritic[n][25]; break;
+      case 'j':  c = letter_w_diacritic[n][26]; break;
+      case 'k':  c = letter_w_diacritic[n][27]; break;
+      case 'l':  c = letter_w_diacritic[n][28]; break;
+      case 'n':  c = letter_w_diacritic[n][29]; break;
+      case 'o':  c = letter_w_diacritic[n][30]; break;
+      case 'r':  c = letter_w_diacritic[n][31]; break;
+      case 's':  c = letter_w_diacritic[n][32]; break;
+      case 't':  c = letter_w_diacritic[n][33]; break;
+      case 'u':  c = letter_w_diacritic[n][34]; break;
+      case 'w':  c = letter_w_diacritic[n][35]; break;
+      case 'y':  c = letter_w_diacritic[n][36]; break;
+      case 'z':  c = letter_w_diacritic[n][37]; break;
+
+      case ALONE:  c = (( !diacritic[n].b ) ? diacritic[n].a : -1);
+                   break;
+
+      default:   c = 0;
+      }
+
+      if ( c > 0 ) {
+        *o++ = c;  s++;
+      } else {
+        *o++ = '{';
+        if ( c == -1 ) {
+          *o++ = ( ( *s == ALONE ) ? ' ' : *s );
+          s++;
+        } else {
+          *o++ = '"';
+        }
+        *o++ = diacritic[n].a;
+        *o++ = '}';
+      }
+      break;
+
+#if (ISO_8859 == 0)
+    case 0x8: case 0x9:
+      *o++ = 0x1B; /* <ESC> */
+      *o++ = *s++ - 0x40;
+      break;
+#endif
+
+      default:
+        *o++ = *s++;
+    }
+  }
+
+  len = o - oo;
+  o = oo;
+
+  if ( (oo = (Byte *)NSLDAPI_REALLOC( o, len )) == NULL ) {
+    NSLDAPI_FREE( o );
+    return( 1 );
+  }
+
+  if ( free_input ) {
+    NSLDAPI_FREE( *bufp );
+  }
+  *bufp = (char *) oo;
+  *buflenp = len;
+  return( 0 );
+}
+
+
+static int
+hh_to_c( Byte *h )
+{
+  Byte c;
+
+  if ( (*h >= '0') && (*h <= '9') )      c = *h++ - '0';
+  else if ( (*h >= 'A') && (*h <= 'F') ) c = *h++ - 'A' + 10;
+  else if ( (*h >= 'a') && (*h <= 'f') ) c = *h++ - 'a' + 10;
+  else return -1;
+
+  c <<= 4;
+
+  if ( (*h >= '0') && (*h <= '9') )      c |= *h - '0';
+  else if ( (*h >= 'A') && (*h <= 'F') ) c |= *h - 'A' + 10;
+  else if ( (*h >= 'a') && (*h <= 'f') ) c |= *h - 'a' + 10;
+  else return -1;
+
+  return c;
+}
+
+
+static Byte *
+cc_to_t61( Byte *o, Byte *s )
+{
+  int n, c = 0;
+
+  switch ( *(s + 1) ) {
+
+  case '`':  c = -1;   break;    /* <grave-accent> */
+
+  case '!':
+    switch ( *s ) {
+    case '!':  c = 0x7C;  break;  /* <vertical-line> */
+    case '(':  c = 0x7B;  break;  /* <left-curly-bracket> */
+    case '-':  c = 0xAD;  break;  /* <upwards-arrow> */
+    default:   c = -1;            /* <grave-accent> */
+    }
+    break;
+
+#if (ISO_8859 == 1) || (ISO_8859 == 2) || (ISO_8859 == 3) || \
+    (ISO_8859 == 4) || (ISO_8859 == 9)
+  case 0xB4:
+#endif
+  case '\'': c = -2;  break;    /* <acute-accent> */
+
+  case '^':  c = -3;  break;    /* <circumflex-acent> */
+
+  case '>':
+    switch ( *s ) {
+    case ')':  c = 0x5D;  break;  /* <right-square-bracket> */
+    case '>':  c = 0xBB;  break;  /* <right-angle-quotation> */
+    case '-':  c = 0xAE;  break;  /* <rightwards-arrow> */
+    default:   c = -3;            /* <circumflex-acent> */
+    }
+    break;
+
+  case '~':
+  case '?':  c = -4;  break;        /* <tilde> */
+
+#if (ISO_8859 == 1) || (ISO_8859 == 4) || (ISO_8859 == 9)
+  case 0xAF:  c = -5;  break;       /* <macron> */
+#endif
+
+  case '-':
+    switch ( *s ) {
+    case '-':  c = 0xFF; break; /* <soft-hyphen> */
+    case '<':  c = 0xAC; break; /* <leftwards arrow> */
+    case '+':  c = 0xB1; break; /* <plus-minus> */
+    case 'd':  c = 0xF3; break; /* <eth> */
+    default:   c = -5;          /* <macron> */
+    }
+    break;
+
+#if (ISO_8859 == 2) || (ISO_8859 == 3)
+  case 0xA2:  c = -6;  break;            /* <breve> */
+#endif
+
+  case '(':
+    if ( *s == '<' ) c = 0x5B;  /* <left-square-bracket> */
+    else             c = -6;    /* <breve> */
+    break;
+
+#if (ISO_8859 == 2) || (ISO_8859 == 3) || (ISO_8859 == 4)
+  case 0xFF:  c = -7;  break;    /* <dot-accent> */
+#endif
+
+  case '.':
+    switch ( *s ) {
+    case 'i':  c = 0xF5; break; /* <dotless-i> */
+    case 'L':  c = 0xE7; break; /* <L-middle-dot> */
+    case 'l':  c = 0xF7; break; /* <l-middle-dot> */
+    default:   c = -7;          /* <dot-accent> */
+    }
+    break;
+
+#if (ISO_8859 == 1) || (ISO_8859 == 2) || (ISO_8859 == 3) || \
+    (ISO_8859 == 4) || (ISO_8859 == 9)
+  case 0xA8:  c = -8; break; /* <diaeresis> */
+#endif
+
+  case ':':
+    if ( *s == '-')  c = 0xB8; /* <division-sign> */
+    else             c = -8;   /* <diaeresis> */
+    break;
+
+#if (ISO_8859 == 1) || (ISO_8859 == 2) || (ISO_8859 == 3) || \
+    (ISO_8859 == 4) || (ISO_8859 == 9) || (ISO_8859 == 10)
+  case 0xB0:
+#endif
+  case '0':  c = -10;  break;  /* <ring-above> */
+
+#if (ISO_8859 == 1) || (ISO_8859 == 2) || (ISO_8859 == 3) || \
+    (ISO_8859 == 4) || (ISO_8859 == 9)
+  case 0xB8:
+#endif
+  case ',':  c = -11; break; /* <cedilla> */
+
+#if (ISO_8859 == 2)
+  case 0xBD:
+#endif
+  case '"':  c = -13; break; /* <double-acute-accent> */
+
+#if (ISO_8859 == 2) || (ISO_8859 == 4)
+  case 0xB2:
+#endif
+  case ';':  c = -14; break; /* <ogonek> */
+
+#if (ISO_8859 == 2) || (ISO_8859 == 4)
+  case 0xB7:  c = -15;  break;  /* <caron> */
+#endif
+
+  case ')':
+    if ( *s == '!' )  c = 0x7D;  /* <left-curly-bracket> */
+    break;
+
+  case '<':
+    if ( *s == '<' )  c = 0xAB;  /* <left-angle-quotation> */
+    else              c = -15;   /* <caron> */
+    break;
+
+  case '/':
+    switch ( *s ) {
+    case '/':  c = 0x5C; break; /* <reverse-solidus> */
+    case 'D':  c = 0xE2; break; /* <D-stroke> */
+    case 'd':  c = 0xF2; break; /* <d-stroke> */
+    case 'H':  c = 0xE4; break; /* <H-stroke> */
+    case 'h':  c = 0xF4; break; /* <h-stroke> */
+    case 'L':  c = 0xE8; break; /* <L-stroke> */
+    case 'l':  c = 0xF8; break; /* <l-stroke> */
+    case 'O':  c = 0xE9; break; /* <O-stroke> */
+    case 'o':  c = 0xF9; break; /* <o-stroke> */
+    case 'T':  c = 0xED; break; /* <T-stroke> */
+    case 't':  c = 0xFD; break; /* <t-stroke> */
+    }
+    break;
+
+  case '2':
+    if ( *s == '1' )  c = 0xBD;    /* <one-half> */
+    break;
+
+  case '4':
+    switch ( *s ) {
+    case '1':  c = 0xBC; break; /* <one-quarter> */
+    case '3':  c = 0xBE; break; /* <three-quarters> */
+    }
+    break;
+
+  case '6':
+    switch ( *s ) {
+    case '\'': c = 0xA9; break; /* <left-single-quotation> */
+    case '"':  c = 0xAA; break; /* <left-double-quotation> */
+    }
+    break;
+
+  case '8':
+    switch ( *s ) {
+    case '1':  c = 0xDC; break; /* <one-eighth> */
+    case '3':  c = 0xDD; break; /* <three-eighths> */
+    case '5':  c = 0xDE; break; /* <five-eighths> */
+    case '7':  c = 0xDF; break; /* <seven-eighths> */
+    case 'M':  c = 0xD5; break; /* <eighth-note> */
+    }
+    break;
+
+  case '9':
+    switch ( *s ) {
+    case '\'': c = 0xB9; break; /* <right-single-quotation> */
+    case '"':  c = 0xBA; break; /* <right-double-quotation> */
+    }
+    break;
+
+  case 'A':
+    if ( *s == 'A' )  c = -10;  /* <ring-above> + <A> */
+    break;
+
+  case 'a':
+    switch ( *s ) {
+    case '-':  c = 0xE3; break; /* <femenine-ordinal-a> */
+    case 'a':  c = -10;  break; /* <ring-above> + <a> */
+    }
+    break;
+
+  case 'B':
+    if ( *s == 'B' )  c = 0xD7; /* <broken-bar> */
+    break;
+
+  case 'b':
+    if ( *s == 'N' )  c = 0xA6;  /* <number-sign> */
+    break;
+
+  case 'd':
+    if ( *s == 'P' )  c = 0xA3;  /* <pound-sign> */
+    break;
+
+  case 'E':
+    switch ( *s ) {
+    case 'S':  c = 0xA7; break; /* <section-sign> */
+    case 'A':  c = 0xE1; break; /* <AE> */
+    case 'O':  c = 0xEA; break; /* <OE> */
+    }
+    break;
+
+  case 'e':
+    switch ( *s ) {
+    case 'a':  c = 0xF1; break; /* <ae> */
+    case 'o':  c = 0xFA; break; /* <oe> */
+    case 'Y':  c = 0xA5;  break;  /* <yen-sign> */
+    }
+    break;
+
+  case 'G':
+    switch ( *s ) {
+    case 'D':  c = 0xB0; break; /* <degree-sign> */
+    case 'N':  c = 0xEE; break; /* <Eng> */
+    }
+    break;
+
+  case 'g':
+    switch ( *s ) {
+    case 'R':  c = 0xD2; break;  /* <registered-sign> */
+    case 'n':  c = 0xFE; break; /* <eng> */
+    }
+    break;
+
+  case 'H':
+    if ( *s == 'T' )  c = 0xEC;  /* <Thorn> */
+    break;
+
+  case 'h':
+    if ( *s == 't' )  c = 0xFC; /* <thorn> */
+    break;
+
+  case 'I':
+    switch ( *s ) {
+    case 'P':  c = 0xB6; break;  /* <pilcrow-sign> */
+    case '!':  c = 0xA1; break; /* <inverted-exclamation> */
+    case '?':  c = 0xBF; break; /* <inverted-question> */
+    }
+    break;
+
+  case 'J':
+    if ( *s == 'I' )  c = 0xE6; /* <IJ> */
+    break;
+
+  case 'j':
+    if ( *s == 'i' )  c = 0xF6;  /* <ij> */
+    break;
+
+  case 'k':
+    if ( *s == 'k' )  c = 0xF0; /* <kra> */
+    break;
+
+  case 'M':
+    switch ( *s ) {
+    case '.':  c = 0xB7; break; /* <middle-dot> */
+    case '-':  c = 0xD0; break; /* <em-dash> */
+    case 'T':  c = 0xD4; break; /* <trade-mark-sign> */
+    }
+    break;
+
+  case 'm':
+    switch ( *s ) {
+    case '\'':                  /* <macron> RFC 1345 */
+    case ' ':  c = -5;   break; /* <macron> */
+    case 'O':  c = 0xE0; break; /* <Ohm sign> */
+    }
+    break;
+
+  case 'n':
+    if ( *s == '\'' )  c = 0xEF; /* <n-preceded-by-apostrophe> */
+    break;
+
+  case 'O':
+    switch ( *s ) {
+    case 'D':  c = 0xA4; break; /* <dollar-sign> */
+    case 'N':  c = 0xD6; break; /* <not-sign> */
+    }
+    break;
+
+  case 'o':
+    switch ( *s ) {
+    case 'C':  c = 0xD3; break; /* <copyright-sign> */
+    case '-':  c = 0xEB; break; /* <masculine-ordinal-o> */
+    }
+    break;
+
+  case 'S':
+    switch ( *s ) {
+    case '1':  c = 0xD1; break; /* <superscript-1> */
+    case '2':  c = 0xB2; break; /* <superscript-2> */
+    case '3':  c = 0xB3; break; /* <superscript-3> */
+    case 'N':  c = 0xA0; break; /* <no-break-space> */
+    }
+    break;
+
+  case 's':
+    if ( *s == 's' )  c = 0xFB; /* <sharp-s> */
+    break;
+
+  case 't':
+    if ( *s == 'C' )  c = 0xA2; /* <cent-sign> */
+    break;
+
+  case 'u':
+    if ( *s == 'C' )  c = 0xA8; /* <currency-sign> */
+    break;
+
+  case 'v':
+    if ( *s == '-' )  c = 0xAF; /* <downwards-arrow> */
+    break;
+
+  case 'X':
+    if ( *s == '*' )  c = 0xB4; /* <multiplication-sign> */
+    break;
+
+  case 'y':
+    if ( *s == 'M' )  c = 0xB5; /* <micro-sign> */
+    break;
+  }
+
+  if ( c > 0 ) {
+    *o++ = c;
+    return o;
+  } else if ( !c )
+    return NULL;
+
+  /* else: c < 0 */
+  n = -c;
+  switch ( *s ) {
+
+  case 'A':  c = letter_w_diacritic[n][0]; break;
+  case 'C':  c = letter_w_diacritic[n][1]; break;
+  case 'D':  c = letter_w_diacritic[n][2]; break;
+  case 'E':  c = letter_w_diacritic[n][3]; break;
+  case 'G':  c = letter_w_diacritic[n][4]; break;
+  case 'H':  c = letter_w_diacritic[n][5]; break;
+  case 'I':  c = letter_w_diacritic[n][6]; break;
+  case 'J':  c = letter_w_diacritic[n][7]; break;
+  case 'K':  c = letter_w_diacritic[n][8]; break;
+  case 'L':  c = letter_w_diacritic[n][9]; break;
+  case 'N':  c = letter_w_diacritic[n][10]; break;
+  case 'O':  c = letter_w_diacritic[n][11]; break;
+  case 'R':  c = letter_w_diacritic[n][12]; break;
+  case 'S':  c = letter_w_diacritic[n][13]; break;
+  case 'T':  c = letter_w_diacritic[n][14]; break;
+  case 'U':  c = letter_w_diacritic[n][15]; break;
+  case 'W':  c = letter_w_diacritic[n][16]; break;
+  case 'Y':  c = letter_w_diacritic[n][17]; break;
+  case 'Z':  c = letter_w_diacritic[n][18]; break;
+
+  case 'a':  c = letter_w_diacritic[n][19]; break;
+  case 'c':  c = letter_w_diacritic[n][20]; break;
+  case 'd':  c = letter_w_diacritic[n][21]; break;
+  case 'e':  c = letter_w_diacritic[n][22]; break;
+  case 'g':  c = letter_w_diacritic[n][23]; break;
+  case 'h':  c = letter_w_diacritic[n][24]; break;
+  case 'i':  c = letter_w_diacritic[n][25]; break;
+  case 'j':  c = letter_w_diacritic[n][26]; break;
+  case 'k':  c = letter_w_diacritic[n][27]; break;
+  case 'l':  c = letter_w_diacritic[n][28]; break;
+  case 'n':  c = letter_w_diacritic[n][29]; break;
+  case 'o':  c = letter_w_diacritic[n][30]; break;
+  case 'r':  c = letter_w_diacritic[n][31]; break;
+  case 's':  c = letter_w_diacritic[n][32]; break;
+  case 't':  c = letter_w_diacritic[n][33]; break;
+  case 'u':  c = letter_w_diacritic[n][34]; break;
+  case 'w':  c = letter_w_diacritic[n][35]; break;
+  case 'y':  c = letter_w_diacritic[n][36]; break;
+  case 'z':  c = letter_w_diacritic[n][37]; break;
+
+  case '\'':
+  case ' ':  c = -1; break;
+
+  default:   c = 0;
+  }
+
+  if ( !c )
+    return NULL;
+
+  *o++ = n + 0xC0;
+  *o++ = ( ( (*s == ' ') || (*s == '\'') ) ? ALONE : *s );
+  return o;
+}
+
+
+/* --- routine to convert from ISO 8859-n to T.61 --- */
+
+int
+ldap_8859_to_t61( char **bufp, unsigned long *buflenp, int free_input )
+{
+  Byte		*s, *oo, *o, *aux;
+  int		c;
+  unsigned long len; 
+  Couple	*cc;
+
+  LDAPDebug( LDAP_DEBUG_TRACE, "ldap_8859_to_t61 input length: %ld\n",
+	*buflenp, 0, 0 );
+
+  len = *buflenp;
+  s = (Byte *) *bufp;
+
+  if ( (o = oo = (Byte *)NSLDAPI_MALLOC( 2 * len + 64 )) == NULL ) {
+        return( 1 );
+  }
+
+  while ( (char *)s - *(char **)bufp < len ) {
+    switch( *s >> 5 ) {
+
+    case 2:
+      switch ( *s ) {
+
+      case '^':  *o++ = 0xC3; *o++ = ALONE; s++; break;
+
+      case '\\':
+        s++;
+        if ( (c = hh_to_c( s )) != -1 ) {
+          *o++ = c;
+          s += 2;
+        } else
+          *o++ = '\\';
+        break;
+
+      default:  *o++ = *s++;
+      }
+      break;
+
+    case 3:
+      switch ( *s ) {
+
+      case '`':  *o++ = 0xC1; *o++ = ALONE; s++; break;
+      case '~':  *o++ = 0xC4; *o++ = ALONE; s++; break;
+
+      case '{':
+        s++;
+        if ( *(s + 2) == '}' ) {
+          if ( (aux = cc_to_t61( o, s )) != NULL ) {
+            o = aux;
+            s += 3;
+          } else {
+            *o++ = '{';
+          }
+        } else if ( (*(s + 3) == '}') && ( (*s == 'x') || (*s == 'X') ) &&
+                    ( (c = hh_to_c( s + 1 )) != -1 ) ) {
+          *o++ = c;
+          s += 4;
+        } else {
+          *o++ = '{';
+        }
+        break;
+
+      default:
+        *o++ = *s++;
+      }
+      break;
+
+#if (ISO_8859 == 0)
+    case 4: case 5: case 6: case 7:
+      s++;
+      break;
+#else
+    case 5: case 6: case 7:
+# if (ISO_8859 == 1) || (ISO_8859 == 2) || (ISO_8859 == 3) || \
+     (ISO_8859 == 4) || (ISO_8859 == 9) || (ISO_8859 == 10)
+      if ( (*(cc = &trans_iso8859_t61[ *s - 0xA0 ])).a ) {
+	*o++ = (*cc).a;
+	if ( (*cc).b )  *o++ = (*cc).b;
+      }
+# endif
+      s++;
+      break;
+#endif
+
+    default:
+      *o++ = *s++;
+    }
+  }
+
+  len = o - oo;
+  o = oo;
+
+  if ( (oo = (Byte *)NSLDAPI_REALLOC( o, len )) == NULL ) {
+    NSLDAPI_FREE( o );
+    return( 1 );
+  }
+
+  if ( free_input ) {
+    NSLDAPI_FREE( *bufp );
+  }
+  *bufp = (char *) oo;
+  *buflenp = len;
+  return( 0 );
+}
+
+
+#ifdef NOT_NEEDED_IN_LIBLDAP	/* mcs@umich.edu 12 Oct 1995 */
+/* --- routine to convert "escaped" (\hh) characters to 8bits --- */
+
+void convert_escaped_to_8bit( s )
+char	*s;
+{
+  char	*o = s;
+  int	c;
+
+  while ( *s ) {
+    if ( *s == '\\' ) {
+      if ( (c = hh_to_c( ++s )) != -1 ) {
+	*o++ = c;
+	s += 2;
+      } else
+        *o++ = '\\';
+    } else
+      *o++ = *s++;
+  }
+  *o = '\0';
+}
+
+/* --- routine to convert 8bits characters to the "escaped" (\hh) form --- */
+
+char *convert_8bit_to_escaped( s )
+Byte  *s;
+{
+  Byte	*o, *oo;
+  Byte	n;
+
+  if ( (o = oo = (Byte *)NSLDAPI_MALLOC( 2 * strlen( s ) + 64 )) == NULL ) {
+        return( NULL );
+  }
+
+  while ( *s ) {
+    if ( *s < 0x80 )
+      *o++ = *s++;
+    else {
+      *o++ = '\\';
+      n = *s >> 4;
+      *o++ = ((n < 0xA) ? '0' : 'A' - 0xA) + n;
+      n = *s++ & 0x0F;
+      *o++ = ((n < 0xA) ? '0' : 'A' - 0xA) + n;
+    }
+  }
+  *o = '\0';
+
+  o = oo;
+
+  if ( (oo = (Byte *)NSLDAPI_REALLOC( o, strlen( o ) + 1 )) == NULL ) {
+    NSLDAPI_FREE( o );
+    return( NULL );
+  }
+
+  return( (char *)oo );
+}
+
+/* --- routine to convert from T.61 to printable characters --- */
+
+/*
+   printable characters [RFC 1488]: 'A'..'Z', 'a'..'z', '0'..'9',
+       '\'', '(', ')', '+', ',', '-', '.', '/', ':', '?, ' '.
+
+   that conversion is language dependent.
+*/
+
+static Couple last_t61_printabled[32] = {
+	{0,0},     {'A','E'}, {'D',0},   {0,0},
+	{'H',0},   {0,0},     {'I','J'}, {'L',0},
+	{'L',0},   {'O',0},   {'O','E'}, {0,0},
+	{'T','H'}, {'T',0},   {'N','G'}, {'n',0},
+	{'k',0},   {'a','e'}, {'d',0},   {'d',0},
+	{'h',0},   {'i',0},   {'i','j'}, {'l',0},
+	{'l',0},   {'o',0},   {'o','e'}, {'s','s'},
+	{'t','h'}, {'t',0},   {'n','g'}, {0,0}
+};
+
+char *t61_printable( s )
+Byte  *s;
+{
+  Byte   *o, *oo;
+  Byte   n;
+  Couple *cc;
+
+  if ( (o = oo = (Byte *)NSLDAPI_MALLOC( 2 * strlen( s ) + 64 )) == NULL ) {
+        return( NULL );
+  }
+
+  while ( *s ) {
+    if ( ( (*s >= 'A') && (*s <= 'Z') ) ||
+         ( (*s >= 'a') && (*s <= 'z') ) ||
+         ( (*s >= '0') && (*s <= '9') ) ||
+         ( (*s >= '\'') && (*s <= ')') ) ||
+         ( (*s >= '+') && (*s <= '/') ) ||
+         ( *s == '?' ) || ( *s == ' ' ) )
+      *o++ = *s++;
+    else {
+      if ( *s >= 0xE0 ) {
+	if ( (*(cc = &last_t61_printabled[ *s - 0xE0 ])).a ) {
+          *o++ = (*cc).a;
+          if ( (*cc).b )  *o++ = (*cc).b;
+        }
+      }
+      else if ( (*s >> 4) == 0xC ) {
+        switch ( *s ) {
+	case 0xCA:			/* ring */
+	  switch ( *(s + 1) ) {
+	  case 'A':  *o++ = 'A'; *o++ = 'A'; s++; break; /* Swedish */
+	  case 'a':  *o++ = 'a'; *o++ = 'a'; s++; break; /* Swedish */
+	  }
+	  break;
+
+	case 0xC8:			/* diaeresis */
+	  switch ( *(s + 1) ) {
+	  case 'Y':  *o++ = 'I'; *o++ = 'J'; s++; break; /* Dutch */
+	  case 'y':  *o++ = 'i'; *o++ = 'j'; s++; break; /* Dutch */
+          }
+	  break;
+        }
+      }
+      s++;
+    }
+  }
+  *o = '\0';
+
+  o = oo;
+
+  if ( (oo = (Byte *)NSLDAPI_REALLOC( o, strlen( o ) + 1 )) == NULL ) {
+    NSLDAPI_FREE( o );
+    return( NULL );
+  }
+
+  return( (char *)oo );
+}
+#endif /* NOT_NEEDED_IN_LIBLDAP */	/* mcs@umich.edu 12 Oct 1995 */
+
+#endif /* LDAP_CHARSET_8859 */
+#endif /* STR_TRANSLATION */
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/cldap.c
@@ -0,0 +1,585 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ *  Copyright (c) 1990, 1994 Regents of the University of Michigan.
+ *  All rights reserved.
+ */
+/*
+ *  cldap.c - synchronous, retrying interface to the cldap protocol
+ */
+
+
+#ifdef CLDAP
+
+XXX not MT-safe XXX
+
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1990, 1994 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#ifdef macintosh
+#include <stdlib.h>
+#include "macos.h"
+#else /* macintosh */
+#ifdef DOS
+#include "msdos.h"
+#else /* DOS */
+#ifdef _WINDOWS
+#include <windows.h>
+#else /* _WINDOWS */
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#endif /* _WINDOWS */
+#endif /* DOS */
+#endif /* macintosh */
+
+#include "ldap-int.h"
+
+#define DEF_CLDAP_TIMEOUT	3
+#define DEF_CLDAP_TRIES		4
+
+#ifndef INADDR_LOOPBACK
+#define INADDR_LOOPBACK	((unsigned long) 0x7f000001)
+#endif
+
+
+struct cldap_retinfo {
+	int		cri_maxtries;
+	int		cri_try;
+	int		cri_useaddr;
+	long		cri_timeout;
+};
+
+#ifdef NEEDPROTOS
+static int add_addr( LDAP *ld, struct sockaddr *sap );
+static int cldap_result( LDAP *ld, int msgid, LDAPMessage **res,
+	struct cldap_retinfo *crip, char *base );
+static int cldap_parsemsg( LDAP *ld, int msgid, BerElement *ber,
+	LDAPMessage **res, char *base );
+#else /* NEEDPROTOS */
+static int add_addr();
+static int cldap_result();
+static int cldap_parsemsg();
+#endif /* NEEDPROTOS */
+
+/*
+ * cldap_open - initialize and connect to an ldap server.  A magic cookie to
+ * be used for future communication is returned on success, NULL on failure.
+ *
+ * Example:
+ *	LDAP	*ld;
+ *	ld = cldap_open( hostname, port );
+ */
+
+LDAP *
+cldap_open( char *host, int port )
+{
+    int 		s;
+    ldap_x_in_addr_t	address;
+    struct sockaddr_in 	sock;
+    struct hostent	*hp;
+    LDAP		*ld;
+    char		*p;
+    int			i;
+
+    LDAPDebug( LDAP_DEBUG_TRACE, "cldap_open\n", 0, 0, 0 );
+
+    if ( port == 0 ) {
+	    port = LDAP_PORT;
+    }
+
+    if ( (s = socket( AF_INET, SOCK_DGRAM, 0 )) < 0 ) {
+	return( NULL );
+    }
+
+    sock.sin_addr.s_addr = 0;
+    sock.sin_family = AF_INET;
+    sock.sin_port = 0;
+    if ( bind(s, (struct sockaddr *) &sock, sizeof(sock)) < 0)  {
+	close( s );
+	return( NULL );
+    }
+
+    if (( ld = ldap_init( host, port )) == NULL ) {
+	close( s );
+	return( NULL );
+    }
+    if ( (ld->ld_sbp->sb_fromaddr = (void *)NSLDAPI_CALLOC( 1,
+	    sizeof( struct sockaddr ))) == NULL ) {
+	NSLDAPI_FREE( ld );
+	close( s );
+	return( NULL );
+    }	
+    ld->ld_sbp->sb_sd = s;
+    ld->ld_sbp->sb_naddr = 0;
+    ld->ld_version = LDAP_VERSION2;
+
+    sock.sin_family = AF_INET;
+    sock.sin_port = htons( port );
+
+    /*
+     * 'host' may be a space-separated list.
+     */
+    if ( host != NULL ) {
+	for ( ; host != NULL; host = p ) {
+	    if (( p = strchr( host, ' ' )) != NULL ) {
+		for (*p++ = '\0'; *p == ' '; p++) {
+		    ;
+		}
+	    }
+
+	    if ( (address = inet_addr( host )) == -1 ) {
+/* XXXmcs: need to use DNS callbacks here XXX */
+XXX
+		if ( (hp = gethostbyname( host )) == NULL ) {
+		    LDAP_SET_ERRNO( ld, EHOSTUNREACH );
+		    continue;
+		}
+
+		for ( i = 0; hp->h_addr_list[ i ] != 0; ++i ) {
+		    SAFEMEMCPY( (char *)&sock.sin_addr.s_addr,
+			    (char *)hp->h_addr_list[ i ],
+			    sizeof(sock.sin_addr.s_addr));
+		    if ( add_addr( ld, (struct sockaddr *)&sock ) < 0 ) {
+			close( s );
+			NSLDAPI_FREE( ld );
+			return( NULL );
+		    }
+		}
+
+	    } else {
+		sock.sin_addr.s_addr = address;
+		if ( add_addr( ld, (struct sockaddr *)&sock ) < 0 ) {
+		    close( s );
+		    NSLDAPI_FREE( ld );
+		    return( NULL );
+		}
+	    }
+
+	    if ( ld->ld_host == NULL ) {
+		    ld->ld_host = nsldapi_strdup( host );
+	    }
+	}
+
+    } else {
+	address = INADDR_LOOPBACK;
+	sock.sin_addr.s_addr = htonl( address );
+	if ( add_addr( ld, (struct sockaddr *)&sock ) < 0 ) {
+	    close( s );
+	    NSLDAPI_FREE( ld );
+	    return( NULL );
+	}
+    }
+
+    if ( ld->ld_sbp->sb_addrs == NULL
+	    || ( ld->ld_defconn = nsldapi_new_connection( ld, NULL, 1,0,0 )) == NULL ) {
+	NSLDAPI_FREE( ld );
+	return( NULL );
+    }
+
+    ld->ld_sbp->sb_useaddr = ld->ld_sbp->sb_addrs[ 0 ];
+    cldap_setretryinfo( ld, 0, 0 );
+
+#ifdef LDAP_DEBUG
+    putchar( '\n' );
+    for ( i = 0; i < ld->ld_sbp->sb_naddr; ++i ) {
+	LDAPDebug( LDAP_DEBUG_TRACE, "end of cldap_open address %d is %s\n",
+		i, inet_ntoa( ((struct sockaddr_in *)
+		ld->ld_sbp->sb_addrs[ i ])->sin_addr ), 0 );
+    }
+#endif
+
+    return( ld );
+}
+
+
+
+void
+cldap_close( LDAP *ld )
+{
+	ldap_ld_free( ld, NULL, NULL, 0 );
+}
+
+
+void
+cldap_setretryinfo( LDAP *ld, int tries, int timeout )
+{
+    ld->ld_cldaptries = ( tries <= 0 ) ? DEF_CLDAP_TRIES : tries;
+    ld->ld_cldaptimeout = ( timeout <= 0 ) ? DEF_CLDAP_TIMEOUT : timeout;
+}
+
+
+int
+cldap_search_s( LDAP *ld, char *base, int scope, char *filter, char **attrs,
+	int attrsonly, LDAPMessage **res, char *logdn )
+{
+    int				ret, msgid;
+    struct cldap_retinfo	cri;
+
+    *res = NULLMSG;
+
+    (void) memset( &cri, 0, sizeof( cri ));
+
+    if ( logdn != NULL ) {
+	ld->ld_cldapdn = logdn;
+    } else if ( ld->ld_cldapdn == NULL ) {
+	ld->ld_cldapdn = "";
+    }
+
+    do {
+	if ( cri.cri_try != 0 ) {
+		--ld->ld_msgid;	/* use same id as before */
+	}
+	ld->ld_sbp->sb_useaddr = ld->ld_sbp->sb_addrs[ cri.cri_useaddr ];
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "cldap_search_s try %d (to %s)\n",
+	    cri.cri_try, inet_ntoa( ((struct sockaddr_in *)
+	    ld->ld_sbp->sb_useaddr)->sin_addr ), 0 );
+
+	    if ( (msgid = ldap_search( ld, base, scope, filter, attrs,
+		attrsonly )) == -1 ) {
+		    return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+	    }
+#ifndef NO_CACHE
+	    if ( ld->ld_cache != NULL && ld->ld_responses != NULL ) {
+		LDAPDebug( LDAP_DEBUG_TRACE, "cldap_search_s res from cache\n",
+			0, 0, 0 );
+		*res = ld->ld_responses;
+		ld->ld_responses = ld->ld_responses->lm_next;
+		return( ldap_result2error( ld, *res, 0 ));
+	    }
+#endif /* NO_CACHE */
+	    ret = cldap_result( ld, msgid, res, &cri, base );
+	} while (ret == -1);
+
+	return( ret );
+}
+
+
+static int
+add_addr( LDAP *ld, struct sockaddr *sap )
+{
+    struct sockaddr	*newsap, **addrs;
+
+    if (( newsap = (struct sockaddr *)NSLDAPI_MALLOC(
+	    sizeof( struct sockaddr ))) == NULL ) {
+	LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+	return( -1 );
+    }
+
+    if ( ld->ld_sbp->sb_naddr == 0 ) {
+	addrs = (struct sockaddr **)NSLDAPI_MALLOC( sizeof(struct sockaddr *));
+    } else {
+	addrs = (struct sockaddr **)NSLDAPI_REALLOC( ld->ld_sbp->sb_addrs,
+		( ld->ld_sbp->sb_naddr + 1 ) * sizeof(struct sockaddr *));
+    }
+
+    if ( addrs == NULL ) {
+	NSLDAPI_FREE( newsap );
+	LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+	return( -1 );
+    }
+
+    SAFEMEMCPY( (char *)newsap, (char *)sap, sizeof( struct sockaddr ));
+    addrs[ ld->ld_sbp->sb_naddr++ ] = newsap;
+    ld->ld_sbp->sb_addrs = (void **)addrs;
+    return( 0 );
+}
+
+
+static int
+cldap_result( LDAP *ld, int msgid, LDAPMessage **res,
+	struct cldap_retinfo *crip, char *base )
+{
+    Sockbuf 		*sb = ld->ld_sbp;
+    BerElement		ber;
+    char		*logdn;
+    int			ret, fromaddr, i;
+    ber_int_t		id;
+    struct timeval	tv;
+
+    fromaddr = -1;
+
+    if ( crip->cri_try == 0 ) {
+	crip->cri_maxtries = ld->ld_cldaptries * sb->sb_naddr;
+	crip->cri_timeout = ld->ld_cldaptimeout;
+	crip->cri_useaddr = 0;
+	LDAPDebug( LDAP_DEBUG_TRACE, "cldap_result tries %d timeout %d\n",
+		ld->ld_cldaptries, ld->ld_cldaptimeout, 0 );
+    }
+
+    if ((tv.tv_sec = crip->cri_timeout / sb->sb_naddr) < 1 ) {
+	tv.tv_sec = 1;
+    }
+    tv.tv_usec = 0;
+
+    LDAPDebug( LDAP_DEBUG_TRACE,
+	    "cldap_result waiting up to %d seconds for a response\n",
+	    tv.tv_sec, 0, 0 );
+    ber_init_w_nullchar( &ber, 0 );
+    nsldapi_set_ber_options( ld, &ber );
+
+    if ( cldap_getmsg( ld, &tv, &ber ) == -1 ) {
+	ret = LDAP_GET_LDERRNO( ld, NULL, NULL );
+	LDAPDebug( LDAP_DEBUG_TRACE, "cldap_getmsg returned -1 (%d)\n",
+		ret, 0, 0 );
+    } else if ( LDAP_GET_LDERRNO( ld, NULL, NULL ) == LDAP_TIMEOUT ) {
+	LDAPDebug( LDAP_DEBUG_TRACE,
+	    "cldap_result timed out\n", 0, 0, 0 );
+	/*
+	 * It timed out; is it time to give up?
+	 */
+	if ( ++crip->cri_try >= crip->cri_maxtries ) {
+	    ret = LDAP_TIMEOUT;
+	    --crip->cri_try;
+	} else {
+	    if ( ++crip->cri_useaddr >= sb->sb_naddr ) {
+		/*
+		 * new round: reset address to first one and
+		 * double the timeout
+		 */
+		crip->cri_useaddr = 0;
+		crip->cri_timeout <<= 1;
+	    }
+	    ret = -1;
+	}
+
+    } else {
+	/*
+	 * Got a response.  It should look like:
+	 * { msgid, logdn, { searchresponse...}}
+	 */
+	logdn = NULL;
+
+	if ( ber_scanf( &ber, "ia", &id, &logdn ) == LBER_ERROR ) {
+	    NSLDAPI_FREE( ber.ber_buf );	/* gack! */
+	    ret = LDAP_DECODING_ERROR;
+	    LDAPDebug( LDAP_DEBUG_TRACE,
+		    "cldap_result: ber_scanf returned LBER_ERROR (%d)\n",
+		    ret, 0, 0 );
+	} else if ( id != msgid ) {
+	    NSLDAPI_FREE( ber.ber_buf );	/* gack! */
+	    LDAPDebug( LDAP_DEBUG_TRACE,
+		    "cldap_result: looking for msgid %d; got %ld\n",
+		    msgid, id, 0 );
+	    ret = -1;	/* ignore and keep looking */
+	} else {
+	    /*
+	     * got a result: determine which server it came from
+	     * decode into ldap message chain
+	     */
+	    for ( fromaddr = 0; fromaddr < sb->sb_naddr; ++fromaddr ) {
+		    if ( memcmp( &((struct sockaddr_in *)
+			    sb->sb_addrs[ fromaddr ])->sin_addr,
+			    &((struct sockaddr_in *)sb->sb_fromaddr)->sin_addr,
+			    sizeof( struct in_addr )) == 0 ) {
+			break;
+		    }
+	    }
+	    ret = cldap_parsemsg( ld, msgid, &ber, res, base );
+	    NSLDAPI_FREE( ber.ber_buf );	/* gack! */
+	    LDAPDebug( LDAP_DEBUG_TRACE,
+		"cldap_result got result (%d)\n", ret, 0, 0 );
+	}
+
+	if ( logdn != NULL ) {
+		NSLDAPI_FREE( logdn );
+	}
+    }
+    
+
+    /*
+     * If we are giving up (successfully or otherwise) then 
+     * abandon any outstanding requests.
+     */
+    if ( ret != -1 ) {
+	i = crip->cri_try;
+	if ( i >= sb->sb_naddr ) {
+	    i = sb->sb_naddr - 1;
+	}
+
+	for ( ; i >= 0; --i ) {
+	    if ( i == fromaddr ) {
+		continue;
+	    }
+	    sb->sb_useaddr = sb->sb_addrs[ i ];
+	    LDAPDebug( LDAP_DEBUG_TRACE, "cldap_result abandoning id %d (to %s)\n",
+		msgid, inet_ntoa( ((struct sockaddr_in *)
+		sb->sb_useaddr)->sin_addr ), 0 );
+	    (void) ldap_abandon( ld, msgid );
+	}
+    }
+
+    LDAP_SET_LDERRNO( ld, ret, NULL, NULL );
+    return( ret );
+}
+
+
+static int
+cldap_parsemsg( LDAP *ld, int msgid, BerElement *ber,
+	LDAPMessage **res, char *base )
+{
+    ber_tag_t	tag;
+    ber_len_t len;
+    int			baselen, slen, rc;
+    char		*dn, *p, *cookie;
+    LDAPMessage		*chain, *prev, *ldm;
+    struct berval	*bv;
+
+    rc = LDAP_DECODING_ERROR;	/* pessimistic */
+    ldm = chain = prev = NULLMSG;
+    baselen = ( base == NULL ) ? 0 : strlen( base );
+    bv = NULL;
+
+    for ( tag = ber_first_element( ber, &len, &cookie );
+	    tag != LBER_ERROR && tag != LBER_END_OF_SEQOFSET
+	    && rc != LDAP_SUCCESS;
+	    tag = ber_next_element( ber, &len, cookie )) {
+	if (( ldm = (LDAPMessage *)NSLDAPI_CALLOC( 1, sizeof(LDAPMessage)))
+		== NULL ) {
+	    rc = LDAP_NO_MEMORY;
+	    break;	/* return with error */
+	} else if (( rc = nsldapi_alloc_ber_with_options( ld, &ldm->lm_ber ))
+		!= LDAP_SUCCESS ) {
+	    break;	/* return with error*/
+	}
+	ldm->lm_msgid = msgid;
+	ldm->lm_msgtype = tag;
+
+	if ( tag == LDAP_RES_SEARCH_RESULT ) {
+	    LDAPDebug( LDAP_DEBUG_TRACE, "cldap_parsemsg got search result\n",
+		    0, 0, 0 );
+
+	    if ( ber_get_stringal( ber, &bv ) == LBER_DEFAULT ) {
+		break;	/* return w/error */
+	    }
+
+	    if ( ber_printf( ldm->lm_ber, "to", tag, bv->bv_val,
+		    bv->bv_len ) == -1 ) {
+		break;	/* return w/error */
+	    }
+	    ber_bvfree( bv );
+	    bv = NULL;
+	    rc = LDAP_SUCCESS;
+
+	} else if ( tag == LDAP_RES_SEARCH_ENTRY ) {
+	    if ( ber_scanf( ber, "{aO", &dn, &bv ) == LBER_ERROR ) {
+		break;	/* return w/error */
+	    }
+	    LDAPDebug( LDAP_DEBUG_TRACE, "cldap_parsemsg entry %s\n", dn, 0, 0 );
+	    if ( dn != NULL && *(dn + ( slen = strlen(dn)) - 1) == '*' &&
+		    baselen > 0 ) {
+		/*
+		 * substitute original searchbase for trailing '*'
+		 */
+		if (( p = (char *)NSLDAPI_MALLOC( slen + baselen )) == NULL ) {
+		    rc = LDAP_NO_MEMORY;
+		    NSLDAPI_FREE( dn );
+		    break;	/* return w/error */
+		}
+		strcpy( p, dn );
+		strcpy( p + slen - 1, base );
+		NSLDAPI_FREE( dn );
+		dn = p;
+	    }
+
+	    if ( ber_printf( ldm->lm_ber, "t{so}", tag, dn, bv->bv_val,
+		    bv->bv_len ) == -1 ) {
+		break;	/* return w/error */
+	    }
+	    NSLDAPI_FREE( dn );
+	    ber_bvfree( bv );
+	    bv = NULL;
+		
+	} else {
+	    LDAPDebug( LDAP_DEBUG_TRACE, "cldap_parsemsg got unknown tag %d\n",
+		    tag, 0, 0 );
+	    rc = LDAP_PROTOCOL_ERROR;
+	    break;	/* return w/error */
+	}
+
+	/* Reset message ber so we can read from it later.  Gack! */
+	ldm->lm_ber->ber_end = ldm->lm_ber->ber_ptr;
+	ldm->lm_ber->ber_ptr = ldm->lm_ber->ber_buf;
+
+#ifdef LDAP_DEBUG
+	if ( ldap_debug & LDAP_DEBUG_PACKETS ) {
+		char msg[80];
+	    sprintf( msg, "cldap_parsemsg add message id %d type %d:\n",
+		    ldm->lm_msgid, ldm->lm_msgtype  );
+		ber_err_print( msg );
+	    ber_dump( ldm->lm_ber, 1 );
+	}
+#endif /* LDAP_DEBUG */
+
+#ifndef NO_CACHE
+	    if ( ld->ld_cache != NULL ) {
+		nsldapi_add_result_to_cache( ld, ldm );
+	    }
+#endif /* NO_CACHE */
+
+	if ( chain == NULL ) {
+	    chain = ldm;
+	} else {
+	    prev->lm_chain = ldm;
+	}
+	prev = ldm;
+	ldm = NULL;
+    }
+
+    /* dispose of any leftovers */
+    if ( ldm != NULL ) {
+	if ( ldm->lm_ber != NULLBER ) {
+	    ber_free( ldm->lm_ber, 1 );
+	}
+	NSLDAPI_FREE( ldm );
+    }
+    if ( bv != NULL ) {
+	ber_bvfree( bv );
+    }
+
+    /* return chain, calling result2error if we got anything at all */
+    *res = chain;
+    return(( *res == NULLMSG ) ? rc : ldap_result2error( ld, *res, 0 ));
+}
+#endif /* CLDAP */
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/compare.c
@@ -0,0 +1,194 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ *  Copyright (c) 1990 Regents of the University of Michigan.
+ *  All rights reserved.
+ */
+/*
+ *  compare.c
+ */
+
+#if 0
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+/*
+ * ldap_compare - perform an ldap compare operation.  The dn
+ * of the entry to compare to and the attribute and value to compare (in
+ * attr and value) are supplied.  The msgid of the response is returned.
+ *
+ * Example:
+ *	ldap_compare( ld, "c=us@cn=bob", "userPassword", "secret" )
+ */
+int
+LDAP_CALL
+ldap_compare( LDAP *ld, const char *dn, const char *attr, const char *value )
+{
+	int		msgid;
+	struct berval	bv;
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_compare\n", 0, 0, 0 );
+
+	bv.bv_val = (char *)value;
+	bv.bv_len = ( value == NULL ) ? 0 : strlen( value );
+
+	if ( ldap_compare_ext( ld, dn, attr, &bv, NULL, NULL, &msgid )
+	    == LDAP_SUCCESS ) {
+		return( msgid );
+	} else {
+		return( -1 );	/* error is in ld handle */
+	}
+}
+
+int
+LDAP_CALL
+ldap_compare_ext( LDAP *ld, const char *dn, const char *attr,
+    const struct berval *bvalue, LDAPControl **serverctrls,
+    LDAPControl **clientctrls, int *msgidp )
+{
+	BerElement	*ber;
+	int		rc, lderr; 
+
+	/* The compare request looks like this:
+	 *	CompareRequest ::= SEQUENCE {
+	 *		entry	DistinguishedName,
+	 *		ava	SEQUENCE {
+	 *			type	AttributeType,
+	 *			value	AttributeValue
+	 *		}
+	 *	}
+	 * and must be wrapped in an LDAPMessage.
+	 */
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_compare_ext\n", 0, 0, 0 );
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( LDAP_PARAM_ERROR );
+	}
+	if ( attr == NULL || bvalue == NULL || bvalue->bv_len == 0
+	    || msgidp == NULL ) {
+		lderr = LDAP_PARAM_ERROR;
+		LDAP_SET_LDERRNO( ld, lderr, NULL, NULL );
+		return( lderr );
+	}
+		
+	if ( dn == NULL ) {
+		dn = "";
+	}
+
+	LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK );
+	*msgidp = ++ld->ld_msgid;
+	LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK );
+
+	/* check the cache */
+	if ( ld->ld_cache_on && ld->ld_cache_compare != NULL ) {
+		LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK );
+		if ( (rc = (ld->ld_cache_compare)( ld, *msgidp,
+		    LDAP_REQ_COMPARE, dn, attr, bvalue )) != 0 ) {
+			*msgidp = rc;
+			LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+			return( LDAP_SUCCESS );
+		}
+		LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+	}
+
+	/* create a message to send */
+	if (( lderr = nsldapi_alloc_ber_with_options( ld, &ber ))
+	    != LDAP_SUCCESS ) {
+		return( lderr );
+	}
+
+	if ( ber_printf( ber, "{it{s{so}}", *msgidp, LDAP_REQ_COMPARE, dn,
+	    attr, bvalue->bv_val, bvalue->bv_len )
+	    == -1 ) {
+		lderr = LDAP_ENCODING_ERROR;
+		LDAP_SET_LDERRNO( ld, lderr, NULL, NULL );
+		ber_free( ber, 1 );
+		return( lderr );
+	}
+
+	if (( lderr = nsldapi_put_controls( ld, serverctrls, 1, ber ))
+	    != LDAP_SUCCESS ) {
+		ber_free( ber, 1 );
+		return( lderr );
+	}
+
+	/* send the message */
+	rc = nsldapi_send_initial_request( ld, *msgidp, LDAP_REQ_COMPARE,
+		(char *)dn, ber );
+	*msgidp = rc;
+	return( rc < 0 ? LDAP_GET_LDERRNO( ld, NULL, NULL ) : LDAP_SUCCESS );
+}
+
+int
+LDAP_CALL
+ldap_compare_s( LDAP *ld, const char *dn, const char *attr,
+    const char *value )
+{
+	struct berval	bv;
+
+	bv.bv_val = (char *)value;
+	bv.bv_len = ( value == NULL ) ? 0 : strlen( value );
+
+	return( ldap_compare_ext_s( ld, dn, attr, &bv, NULL, NULL ));
+}
+
+int
+LDAP_CALL
+ldap_compare_ext_s( LDAP *ld, const char *dn, const char *attr,
+    const struct berval *bvalue, LDAPControl **serverctrls,
+    LDAPControl **clientctrls ) 
+{
+	int		err, msgid;
+	LDAPMessage	*res;
+
+	if (( err = ldap_compare_ext( ld, dn, attr, bvalue, serverctrls,
+	    clientctrls, &msgid )) != LDAP_SUCCESS ) {
+		return( err );
+	}
+
+	if ( ldap_result( ld, msgid, 1, (struct timeval *)NULL, &res )
+	    == -1 ) {
+		return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+	}
+
+	return( ldap_result2error( ld, res, 1 ) );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/compat.c
@@ -0,0 +1,108 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ *  Copyright (c) 1994 The Regents of the University of Michigan.
+ *  All rights reserved.
+ */
+/*
+ *  compat.c - compatibility routines.
+ *
+ */
+
+#if 0
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1994 The Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+#if defined( HPUX10 ) && defined( _REENTRANT ) && !defined(HPUX11)
+extern int h_errno;
+
+struct hostent *
+nsldapi_compat_gethostbyname_r( const char *name, struct hostent *result,
+	char *buffer, int buflen, int *h_errnop )
+{
+    struct hostent_data	*hep;
+
+    if ( buflen < sizeof(struct hostent_data)) {	/* sanity check */
+	*h_errnop = NO_RECOVERY;	/* XXX best error code to use? */
+	return( NULL );
+    }
+
+    hep = (struct hostent_data *)buffer;
+    hep->current = NULL;
+
+    if ( gethostbyname_r( name, result, hep ) == -1) {
+	*h_errnop = h_errno; /* XXX don't see anywhere else to get this */
+	return NULL;
+    }
+    return result;
+}
+
+char *
+nsldapi_compat_ctime_r( const time_t *clock, char *buf, int buflen )
+{
+    NSLDAPI_CTIME1( clock, buf, buflen );
+    return buf;
+}
+#endif /* HPUX10 && _REENTRANT && !HPUX11 */
+
+#if defined(LINUX) || defined(AIX) || defined(HPUX) || defined(_WINDOWS)
+/* 
+ * Copies src to the dstsize buffer at dst. The copy will never 
+ * overflow the destination buffer and the buffer will always be null 
+ * terminated. 
+ */   
+size_t nsldapi_compat_strlcpy(char *dst, const char *src, size_t len) 
+{ 
+	size_t slen = strlen(src); 
+	size_t copied; 
+	
+	if (len == 0) 
+		return (slen); 
+	
+	if (slen >= len) 
+		copied = len - 1; 
+	else 
+		copied = slen; 
+	SAFEMEMCPY(dst, src, copied); 
+	dst[copied] = '\0'; 
+	return (slen); 
+}
+#endif
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/control.c
@@ -0,0 +1,559 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/* control.c - routines to handle ldapv3 controls */
+
+#include "ldap-int.h"
+
+static LDAPControl *ldap_control_dup( LDAPControl *ctrl );
+static int ldap_control_copy_contents( LDAPControl *ctrl_dst,
+    LDAPControl *ctrl_src );
+
+/*
+ * Append a list of LDAPv3 controls to ber.  If ctrls is NULL, use default
+ * set of controls from ld.
+ * Return an LDAP error code (LDAP_SUCCESS if all goes well).
+ * If closeseq is non-zero, we do an extra ber_put_seq() as well.
+ */
+int
+nsldapi_put_controls( LDAP *ld, LDAPControl **ctrls, int closeseq,
+    BerElement *ber )
+{
+	LDAPControl	*c;
+	int		rc, i;
+
+	rc = LDAP_ENCODING_ERROR;	/* the most popular error */
+
+	/* if no controls were passed in, use global list from LDAP * */
+	LDAP_MUTEX_LOCK( ld, LDAP_CTRL_LOCK );
+	if ( ctrls == NULL ) {
+		ctrls = ld->ld_servercontrols;
+	}
+
+	/* if there are no controls then we are done */
+	if ( ctrls == NULL || ctrls[ 0 ] == NULL ) {
+		goto clean_exit;
+	}
+
+	/*
+	 * If we're using LDAPv2 or earlier we can't send any controls, so
+	 * we just ignore them unless one is marked critical, in which case
+	 * we return an error.
+	 */
+	if ( NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION3 ) {
+		for ( i = 0; ctrls != NULL && ctrls[i] != NULL; i++ ) {
+			if ( ctrls[i]->ldctl_iscritical ) {
+				rc = LDAP_NOT_SUPPORTED;
+				goto error_exit;
+			}
+		}
+		goto clean_exit;
+	}
+
+	/*
+	 * encode the controls as a Sequence of Sequence
+	 */
+	if ( ber_printf( ber, "t{", LDAP_TAG_CONTROLS ) == -1 ) {
+		goto error_exit;
+	}
+
+	for ( i = 0; ctrls[i] != NULL; i++ ) {
+		c = ctrls[i];
+
+		if ( ber_printf( ber, "{s", c->ldctl_oid ) == -1 ) {
+			goto error_exit;
+		}
+
+		/* criticality is "BOOLEAN DEFAULT FALSE" */
+		/* therefore, it should only be encoded if it exists AND is TRUE */
+		if ( c->ldctl_iscritical ) {
+			if ( ber_printf( ber, "b", (int)c->ldctl_iscritical )
+			    == -1 ) {
+				goto error_exit;
+			}
+		}
+
+		if ( c->ldctl_value.bv_val != NULL ) {
+			if ( ber_printf( ber, "o", c->ldctl_value.bv_val,
+			    c->ldctl_value.bv_len )
+			    == -1 ) {
+				goto error_exit;
+			}
+		}
+
+		if ( ber_put_seq( ber ) == -1 ) {
+			goto error_exit;
+		}
+	}
+
+	if ( ber_put_seq( ber ) == -1 ) {
+		goto error_exit;
+	}
+
+clean_exit:
+	LDAP_MUTEX_UNLOCK( ld, LDAP_CTRL_LOCK );
+	if ( closeseq && ber_put_seq( ber ) == -1 ) {
+		goto error_exit;
+	}
+	return( LDAP_SUCCESS );
+
+error_exit:
+	LDAP_MUTEX_UNLOCK( ld, LDAP_CTRL_LOCK );
+	LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+	return( rc );
+}
+
+
+/*
+ * Pull controls out of "ber" (if any present) and return them in "controlsp."
+ * Returns an LDAP error code.
+ */
+int
+nsldapi_get_controls( BerElement *ber, LDAPControl ***controlsp )
+{
+	LDAPControl		*newctrl;
+	ber_tag_t		tag;
+	ber_len_t		len;
+	int				rc, maxcontrols, curcontrols;
+	char			*last;
+
+	/*
+	 * Each LDAPMessage can have a set of controls appended
+	 * to it. Controls are used to extend the functionality
+	 * of an LDAP operation (e.g., add an attribute size limit
+	 * to the search operation). These controls look like this:
+	 *
+	 *	Controls ::= SEQUENCE OF Control
+	 *
+	 *	Control ::= SEQUENCE {
+	 *		controlType	LDAPOID,
+	 *		criticality	BOOLEAN DEFAULT FALSE,
+	 *		controlValue	OCTET STRING
+	 *	}
+	 */
+	LDAPDebug( LDAP_DEBUG_TRACE, "=> nsldapi_get_controls\n", 0, 0, 0 );
+
+	*controlsp = NULL;
+
+	/*
+         * check to see if controls were included
+	 */
+	if ( ber_get_option( ber, LBER_OPT_REMAINING_BYTES, &len ) != 0 ) {
+		return( LDAP_DECODING_ERROR );	/* unexpected error */
+	}
+	if ( len == 0 ) {
+		LDAPDebug( LDAP_DEBUG_TRACE,
+		    "<= nsldapi_get_controls no controls\n", 0, 0, 0 );
+		return( LDAP_SUCCESS );			/* no controls */
+	}
+	if (( tag = ber_peek_tag( ber, &len )) != LDAP_TAG_CONTROLS ) {
+		if ( tag == LBER_ERROR ) {
+			LDAPDebug( LDAP_DEBUG_TRACE,
+			    "<= nsldapi_get_controls LDAP_PROTOCOL_ERROR\n",
+			    0, 0, 0 );
+			return( LDAP_DECODING_ERROR );	/* decoding error */
+		}
+		/*
+		 * We found something other than controls.  This should never
+		 * happen in LDAPv3, but we don't treat this is a hard error --
+		 * we just ignore the extra stuff.
+		 */
+		LDAPDebug( LDAP_DEBUG_TRACE,
+		    "<= nsldapi_get_controls ignoring unrecognized data in message (tag 0x%x)\n",
+		    tag, 0, 0 );
+		return( LDAP_SUCCESS );
+	}
+
+	maxcontrols = curcontrols = 0;
+	for ( tag = ber_first_element( ber, &len, &last );
+	    tag != LBER_ERROR && tag != LBER_END_OF_SEQORSET;
+	    tag = ber_next_element( ber, &len, last ) ) {
+		if ( curcontrols >= maxcontrols - 1 ) {
+#define CONTROL_GRABSIZE	5
+			maxcontrols += CONTROL_GRABSIZE;
+			*controlsp = (struct ldapcontrol **)NSLDAPI_REALLOC(
+			    (char *)*controlsp, maxcontrols *
+			    sizeof(struct ldapcontrol *) );
+			if ( *controlsp == NULL ) {
+			    rc = LDAP_NO_MEMORY;
+			    goto free_and_return;
+			}
+		}
+		if (( newctrl = (struct ldapcontrol *)NSLDAPI_CALLOC( 1,
+		    sizeof(LDAPControl))) == NULL ) {
+			rc = LDAP_NO_MEMORY;
+			goto free_and_return;
+		}
+		
+		(*controlsp)[curcontrols++] = newctrl;
+		(*controlsp)[curcontrols] = NULL;
+
+		if ( ber_scanf( ber, "{a", &newctrl->ldctl_oid )
+		    == LBER_ERROR ) {
+			rc = LDAP_DECODING_ERROR;
+			goto free_and_return;
+		}
+
+		/* the criticality is optional */
+		if ( ber_peek_tag( ber, &len ) == LBER_BOOLEAN ) {
+			int		aint;
+
+			if ( ber_scanf( ber, "b", &aint ) == LBER_ERROR ) {
+				rc = LDAP_DECODING_ERROR;
+				goto free_and_return;
+			}
+			newctrl->ldctl_iscritical = (char)aint;	/* XXX lossy cast */
+		} else {
+			/* absent is synonomous with FALSE */
+			newctrl->ldctl_iscritical = 0;
+		}
+
+		/* the control value is optional */
+		if ( ber_peek_tag( ber, &len ) == LBER_OCTETSTRING ) {
+			if ( ber_scanf( ber, "o", &newctrl->ldctl_value )
+			    == LBER_ERROR ) {
+				rc = LDAP_DECODING_ERROR;
+				goto free_and_return;
+			}
+		} else {
+			(newctrl->ldctl_value).bv_val = NULL;
+			(newctrl->ldctl_value).bv_len = 0;
+		}
+
+	}
+
+	if ( tag == LBER_ERROR ) {
+		rc = LDAP_DECODING_ERROR;
+		goto free_and_return;
+	}
+
+	LDAPDebug( LDAP_DEBUG_TRACE,
+	    "<= nsldapi_get_controls found %d controls\n", curcontrols, 0, 0 );
+	return( LDAP_SUCCESS );
+
+free_and_return:;
+	ldap_controls_free( *controlsp );
+	*controlsp = NULL;
+	LDAPDebug( LDAP_DEBUG_TRACE,
+	    "<= nsldapi_get_controls error 0x%x\n", rc, 0, 0 );
+	return( rc );
+}
+
+/*
+ * Skips forward in a ber to find a control tag, then calls on
+ * nsldapi_get_controls() to parse them into an LDAPControl list.
+ * Returns an LDAP error code.
+ */
+int
+nsldapi_find_controls( BerElement *ber, LDAPControl ***controlsp )
+{
+	ber_tag_t tag;
+	ber_len_t len;
+
+	if ( ber == NULLBER ) {
+		return( LDAP_DECODING_ERROR );
+	}
+
+	tag = ber_peek_tag( ber, &len );
+
+	while( tag != LDAP_TAG_CONTROLS && tag != LBER_DEFAULT ) {
+		tag = ber_skip_tag( ber, &len );
+		/* Skip ahead to the next sequence */
+		ber->ber_ptr += len;
+		tag = ber_peek_tag( ber, &len );
+	}
+
+	return( nsldapi_get_controls( ber, controlsp ) );
+}
+
+
+void
+LDAP_CALL
+ldap_control_free( LDAPControl *ctrl )
+{
+	if ( ctrl != NULL ) {
+		if ( ctrl->ldctl_oid != NULL ) {
+			NSLDAPI_FREE( ctrl->ldctl_oid );
+		}
+		if ( ctrl->ldctl_value.bv_val != NULL ) {
+			NSLDAPI_FREE( ctrl->ldctl_value.bv_val );
+		}
+		NSLDAPI_FREE( (char *)ctrl );
+	}
+}
+
+
+void
+LDAP_CALL
+ldap_controls_free( LDAPControl **ctrls )
+{
+	int	i;
+
+	if ( ctrls != NULL ) {
+		for ( i = 0; ctrls[i] != NULL; i++ ) {
+			ldap_control_free( ctrls[i] );
+		}
+		NSLDAPI_FREE( (char *)ctrls );
+	}
+}
+
+LDAPControl *
+LDAP_CALL
+ldap_find_control( const char *oid, LDAPControl **ctrls )
+{
+	int i, foundControl;
+	LDAPControl *Ctrlp = NULL;
+	
+	/* find the control in the list of controls if it exists */
+	if ( ctrls == NULL ) {
+		return ( NULL );
+	} 
+	foundControl = 0;
+	for ( i = 0; (( ctrls[i] != NULL ) && ( !foundControl )); i++ ) {
+		foundControl = !strcmp( ctrls[i]->ldctl_oid, oid );
+	}
+	if ( !foundControl ) {
+		return ( NULL );
+	} else {
+		/* let local var point to the control */
+		Ctrlp = ctrls[i-1];			
+	}
+	
+	return( Ctrlp );
+}
+
+#if 0
+LDAPControl **
+LDAP_CALL
+ldap_control_append( LDAPControl **ctrl_src, LDAPControl *ctrl )
+{
+    int nctrls = 0;
+	LDAPControl **ctrlp;
+	int i;
+
+	if ( NULL == ctrl )
+	    return ( NULL );
+
+	/* Count the existing controls */
+	if ( NULL != ctrl_src ) {
+		while( NULL != ctrl_src[nctrls] ) {
+			nctrls++;
+		}
+	}
+
+	/* allocate the new control structure */
+	if ( ( ctrlp = (LDAPControl **)NSLDAPI_MALLOC( sizeof(LDAPControl *)
+	    * (nctrls + 2) ) ) == NULL ) {
+		return( NULL );
+	}
+	memset( ctrlp, 0, sizeof(*ctrlp) * (nctrls + 2) );
+
+	for( i = 0; i < (nctrls + 1); i++ ) {
+	    if ( i < nctrls ) {
+		    ctrlp[i] = ldap_control_dup( ctrl_src[i] );
+	    } else {
+		    ctrlp[i] = ldap_control_dup( ctrl );
+	    }
+	    if ( NULL == ctrlp[i] ) {
+		    ldap_controls_free( ctrlp );
+		    return( NULL );
+	    }
+	}
+	return ctrlp;
+}
+#endif /* 0 */
+
+
+/*
+ * Replace *ldctrls with a copy of newctrls.
+ * returns 0 if successful.
+ * return -1 if not and set error code inside LDAP *ld.
+ */
+int
+nsldapi_dup_controls( LDAP *ld, LDAPControl ***ldctrls, LDAPControl **newctrls )
+{
+	int	count;
+
+	if ( *ldctrls != NULL ) {
+		ldap_controls_free( *ldctrls );
+	}
+
+	if ( newctrls == NULL || newctrls[0] == NULL ) {
+		*ldctrls = NULL;
+		return( 0 );
+	}
+
+	for ( count = 0; newctrls[ count ] != NULL; ++count ) {
+		;
+	}
+
+	if (( *ldctrls = (LDAPControl **)NSLDAPI_MALLOC(( count + 1 ) *
+	    sizeof( LDAPControl *))) == NULL ) {
+		LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+		return( -1 );
+	}
+	(*ldctrls)[ count ] = NULL;
+
+	for ( count = 0; newctrls[ count ] != NULL; ++count ) {
+		if (( (*ldctrls)[ count ] =
+		    ldap_control_dup( newctrls[ count ] )) == NULL ) {
+			ldap_controls_free( *ldctrls );
+			*ldctrls = NULL;
+			LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+			return( -1 );
+		}
+	}
+
+	return( 0 );
+}
+
+
+/*
+ * return a malloc'd copy of "ctrl" (NULL if memory allocation fails)
+ */
+static LDAPControl *
+/* LDAP_CALL */		/* keep this routine internal for now */
+ldap_control_dup( LDAPControl *ctrl )
+{
+	LDAPControl	*rctrl;
+
+	if (( rctrl = (LDAPControl *)NSLDAPI_MALLOC( sizeof( LDAPControl )))
+	    == NULL ) {
+		return( NULL );
+	}
+
+	if ( ldap_control_copy_contents( rctrl, ctrl ) != LDAP_SUCCESS ) {
+		NSLDAPI_FREE( rctrl );
+		return( NULL );
+	}
+
+	return( rctrl );
+}
+
+
+/*
+ * duplicate the contents of "ctrl_src" and place in "ctrl_dst"
+ */
+static int
+/* LDAP_CALL */		/* keep this routine internal for now */
+ldap_control_copy_contents( LDAPControl *ctrl_dst, LDAPControl *ctrl_src )
+{
+	size_t	len;
+
+	if ( NULL == ctrl_dst || NULL == ctrl_src ) {
+		return( LDAP_PARAM_ERROR );
+	}
+
+	ctrl_dst->ldctl_iscritical = ctrl_src->ldctl_iscritical;
+
+	/* fill in the fields of this new control */
+	if (( ctrl_dst->ldctl_oid = nsldapi_strdup( ctrl_src->ldctl_oid ))
+	    == NULL ) {
+		return( LDAP_NO_MEMORY );
+	}
+
+	len = (size_t)(ctrl_src->ldctl_value).bv_len;
+	if ( ctrl_src->ldctl_value.bv_val == NULL || len <= 0 ) {
+		ctrl_dst->ldctl_value.bv_len = 0;
+		ctrl_dst->ldctl_value.bv_val = NULL;
+	} else {
+		ctrl_dst->ldctl_value.bv_len = len;
+		if (( ctrl_dst->ldctl_value.bv_val = NSLDAPI_MALLOC( len ))
+		    == NULL ) {
+			NSLDAPI_FREE( ctrl_dst->ldctl_oid );
+			return( LDAP_NO_MEMORY );
+		}
+		SAFEMEMCPY( ctrl_dst->ldctl_value.bv_val,
+		    ctrl_src->ldctl_value.bv_val, len );
+	}
+
+	return ( LDAP_SUCCESS );
+}
+
+
+
+/*
+ * build an allocated LDAPv3 control.  Returns an LDAP error code.
+ */
+int
+nsldapi_build_control( char *oid, BerElement *ber, int freeber, char iscritical,
+    LDAPControl **ctrlp )
+{
+	int		rc;
+	struct berval	*bvp;
+
+	if ( ber == NULL ) {
+		bvp = NULL;
+	} else {
+		/* allocate struct berval with contents of the BER encoding */
+		rc = ber_flatten( ber, &bvp );
+		if ( freeber ) {
+			ber_free( ber, 1 );
+		}
+		if ( rc == -1 ) {
+			return( LDAP_NO_MEMORY );
+		}
+	}
+
+	/* allocate the new control structure */
+	if (( *ctrlp = (LDAPControl *)NSLDAPI_MALLOC( sizeof(LDAPControl)))
+	    == NULL ) {
+		if ( bvp != NULL ) {
+			ber_bvfree( bvp );
+		}
+		return( LDAP_NO_MEMORY );
+	}
+
+	/* fill in the fields of this new control */
+	(*ctrlp)->ldctl_iscritical = iscritical;  
+	if (( (*ctrlp)->ldctl_oid = nsldapi_strdup( oid )) == NULL ) {
+		NSLDAPI_FREE( *ctrlp ); 
+		if ( bvp != NULL ) {
+			ber_bvfree( bvp );
+		}
+		return( LDAP_NO_MEMORY );
+	}				
+
+	if ( bvp == NULL ) {
+		(*ctrlp)->ldctl_value.bv_len = 0;
+		(*ctrlp)->ldctl_value.bv_val = NULL;
+	} else {
+		(*ctrlp)->ldctl_value = *bvp;	/* struct copy */
+		NSLDAPI_FREE( bvp );	/* free container, not contents! */
+	}
+
+	return( LDAP_SUCCESS );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/countvalues.c
@@ -0,0 +1,67 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ *  Copyright (c) 1990 Regents of the University of Michigan.
+ *  All rights reserved.
+ */
+/*
+ *  countvalues.c
+ */
+
+#include "ldap-int.h"
+
+int
+LDAP_CALL
+ldap_count_values( char **vals )
+{
+	int	i;
+
+	if ( vals == NULL )
+		return( 0 );
+
+	for ( i = 0; vals[i] != NULL; i++ )
+		;	/* NULL */
+
+	return( i );
+}
+
+int
+LDAP_CALL
+ldap_count_values_len( struct berval **vals )
+{
+	return( ldap_count_values( (char **) vals ) );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/delete.c
@@ -0,0 +1,169 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ *  delete.c
+ */
+
+#if 0
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+/*
+ * ldap_delete - initiate an ldap delete operation. Parameters:
+ *
+ *	ld		LDAP descriptor
+ *	dn		DN of the object to delete
+ *
+ * Example:
+ *	msgid = ldap_delete( ld, dn );
+ */
+int
+LDAP_CALL
+ldap_delete( LDAP *ld, const char *dn )
+{
+	int	msgid;
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_delete\n", 0, 0, 0 );
+
+	if ( ldap_delete_ext( ld, dn, NULL, NULL, &msgid ) == LDAP_SUCCESS ) {
+		return( msgid );
+	} else {
+		return( -1 );	/* error is in ld handle */
+	}
+}
+
+int
+LDAP_CALL
+ldap_delete_ext( LDAP *ld, const char *dn, LDAPControl **serverctrls,
+    LDAPControl **clientctrls, int *msgidp )
+{
+	BerElement	*ber;
+	int		rc, lderr;
+
+	/*
+	 * A delete request looks like this:
+	 *	DelRequet ::= DistinguishedName,
+	 */
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_delete_ext\n", 0, 0, 0 );
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( LDAP_PARAM_ERROR );
+	}
+
+	if ( !NSLDAPI_VALID_LDAPMESSAGE_POINTER( msgidp )) 
+        {
+		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+		return( LDAP_PARAM_ERROR );
+	}
+	if ( dn == NULL ) {
+		dn = "";
+	}
+
+	LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK );
+	*msgidp = ++ld->ld_msgid;
+	LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK );
+
+	/* see if we should add to the cache */
+	if ( ld->ld_cache_on && ld->ld_cache_delete != NULL ) {
+		LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK );
+		if ( (rc = (ld->ld_cache_delete)( ld, *msgidp, LDAP_REQ_DELETE,
+		    dn )) != 0 ) {
+			*msgidp = rc;
+			LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+			return( LDAP_SUCCESS );
+		}
+		LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+	}
+
+	/* create a message to send */
+	if (( lderr = nsldapi_alloc_ber_with_options( ld, &ber ))
+	    != LDAP_SUCCESS ) {
+		return( lderr );
+	}
+
+	if ( ber_printf( ber, "{its", *msgidp, LDAP_REQ_DELETE, dn )
+	    == -1 ) {
+		lderr = LDAP_ENCODING_ERROR;
+		LDAP_SET_LDERRNO( ld, lderr, NULL, NULL );
+		ber_free( ber, 1 );
+		return( lderr );
+	}
+
+	if (( lderr = nsldapi_put_controls( ld, serverctrls, 1, ber ))
+	    != LDAP_SUCCESS ) {
+		ber_free( ber, 1 );
+		return( lderr );
+	}
+
+	/* send the message */
+	rc = nsldapi_send_initial_request( ld, *msgidp, LDAP_REQ_DELETE,
+		(char *)dn, ber );
+	*msgidp = rc;
+	return( rc < 0 ? LDAP_GET_LDERRNO( ld, NULL, NULL ) : LDAP_SUCCESS );
+}
+
+int
+LDAP_CALL
+ldap_delete_s( LDAP *ld, const char *dn )
+{
+	return( ldap_delete_ext_s( ld, dn, NULL, NULL ));
+}
+
+int
+LDAP_CALL
+ldap_delete_ext_s( LDAP *ld, const char *dn, LDAPControl **serverctrls,
+    LDAPControl **clientctrls )
+{
+	int		err, msgid;
+	LDAPMessage	*res;
+
+	if (( err = ldap_delete_ext( ld, dn, serverctrls, clientctrls,
+	    &msgid )) != LDAP_SUCCESS ) {
+		return( err );
+	}
+
+	if ( ldap_result( ld, msgid, 1, (struct timeval *)NULL, &res ) == -1 ) {
+		return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+	}
+
+	return( ldap_result2error( ld, res, 1 ) );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/disptmpl.c
@@ -0,0 +1,770 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ * Copyright (c) 1993, 1994 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+/*
+ * disptmpl.c:  display template library routines for LDAP clients
+ */
+
+#include "ldap-int.h"
+#include "disptmpl.h"
+
+static void free_disptmpl( struct ldap_disptmpl *tmpl );
+static int read_next_tmpl( char **bufp, long *blenp,
+	struct ldap_disptmpl **tmplp, int dtversion );
+
+static char		*tmploptions[] = {
+    "addable", "modrdn",
+    "altview",
+    NULL
+};
+
+
+static unsigned long	tmploptvals[] = {
+    LDAP_DTMPL_OPT_ADDABLE, LDAP_DTMPL_OPT_ALLOWMODRDN,
+    LDAP_DTMPL_OPT_ALTVIEW,
+};
+
+
+static char		*itemtypes[] = {
+    "cis",			"mls",			"dn",
+    "bool",			"jpeg",			"jpegbtn",
+    "fax",			"faxbtn",		"audiobtn",
+    "time",			"date",			"url",
+    "searchact",		"linkact",		"adddnact",
+    "addact",			"verifyact",		"mail",
+    NULL
+};
+
+static unsigned long	itemsynids[] = {
+    LDAP_SYN_CASEIGNORESTR,	LDAP_SYN_MULTILINESTR,	LDAP_SYN_DN,
+    LDAP_SYN_BOOLEAN,		LDAP_SYN_JPEGIMAGE,	LDAP_SYN_JPEGBUTTON,
+    LDAP_SYN_FAXIMAGE,		LDAP_SYN_FAXBUTTON,	LDAP_SYN_AUDIOBUTTON,
+    LDAP_SYN_TIME,		LDAP_SYN_DATE,		LDAP_SYN_LABELEDURL,
+    LDAP_SYN_SEARCHACTION,	LDAP_SYN_LINKACTION,	LDAP_SYN_ADDDNACTION,
+    LDAP_SYN_ADDDNACTION,	LDAP_SYN_VERIFYDNACTION,LDAP_SYN_RFC822ADDR,
+};
+
+
+static char		*itemoptions[] = {
+    "ro",		       		"sort",
+    "1val",				"hide",
+    "required",				"hideiffalse",
+    NULL
+};
+
+
+static unsigned long	itemoptvals[] = {
+    LDAP_DITEM_OPT_READONLY,		LDAP_DITEM_OPT_SORTVALUES,
+    LDAP_DITEM_OPT_SINGLEVALUED,	LDAP_DITEM_OPT_HIDEIFEMPTY,
+    LDAP_DITEM_OPT_VALUEREQUIRED,	LDAP_DITEM_OPT_HIDEIFFALSE,
+};
+
+
+#define ADDEF_CONSTANT	"constant"
+#define ADDEF_ADDERSDN	"addersdn"
+
+
+int
+LDAP_CALL
+ldap_init_templates( char *file, struct ldap_disptmpl **tmpllistp )
+{
+    FILE	*fp;
+    char	*buf;
+    long	rlen, len;
+    int		rc, eof;
+
+    *tmpllistp = NULLDISPTMPL;
+
+    if (( fp = NSLDAPI_FOPEN( file, "r" )) == NULL ) {
+	return( LDAP_TMPL_ERR_FILE );
+    }
+
+    if ( fseek( fp, 0L, SEEK_END ) != 0 ) {	/* move to end to get len */
+	fclose( fp );
+	return( LDAP_TMPL_ERR_FILE );
+    }
+
+    len = ftell( fp );
+
+    if ( fseek( fp, 0L, SEEK_SET ) != 0 ) {	/* back to start of file */
+	fclose( fp );
+	return( LDAP_TMPL_ERR_FILE );
+    }
+
+    if (( buf = NSLDAPI_MALLOC( (size_t)len )) == NULL ) {
+	fclose( fp );
+	return( LDAP_TMPL_ERR_MEM );
+    }
+
+    rlen = fread( buf, 1, (size_t)len, fp );
+    eof = feof( fp );
+    fclose( fp );
+
+    if ( rlen != len && !eof ) {	/* error:  didn't get the whole file */
+	NSLDAPI_FREE( buf );
+	return( LDAP_TMPL_ERR_FILE );
+    }
+
+    rc = ldap_init_templates_buf( buf, rlen, tmpllistp );
+    NSLDAPI_FREE( buf );
+
+    return( rc );
+}
+
+
+int
+LDAP_CALL
+ldap_init_templates_buf( char *buf, long buflen,
+	struct ldap_disptmpl **tmpllistp )
+{
+    int				rc = 0, version;
+    char			**toks;
+    struct ldap_disptmpl	*prevtmpl, *tmpl;
+
+    *tmpllistp = prevtmpl = NULLDISPTMPL;
+
+    if ( nsldapi_next_line_tokens( &buf, &buflen, &toks ) != 2 ||
+	    strcasecmp( toks[ 0 ], "version" ) != 0 ) {
+	nsldapi_free_strarray( toks );
+	return( LDAP_TMPL_ERR_SYNTAX );
+    }
+    version = atoi( toks[ 1 ] );
+    nsldapi_free_strarray( toks );
+    if ( version != LDAP_TEMPLATE_VERSION ) {
+	return( LDAP_TMPL_ERR_VERSION );
+    }
+
+    while ( buflen > 0 && ( rc = read_next_tmpl( &buf, &buflen, &tmpl,
+	    version )) == 0 && tmpl != NULLDISPTMPL ) {
+	if ( prevtmpl == NULLDISPTMPL ) {
+	    *tmpllistp = tmpl;
+	} else {
+	    prevtmpl->dt_next = tmpl;
+	}
+	prevtmpl = tmpl;
+    }
+
+    if ( rc != 0 ) {
+	ldap_free_templates( *tmpllistp );
+    }
+
+    return( rc );
+}
+	    
+
+
+void
+LDAP_CALL
+ldap_free_templates( struct ldap_disptmpl *tmpllist )
+{
+    struct ldap_disptmpl	*tp, *nexttp;
+
+    if ( tmpllist != NULL ) {
+	for ( tp = tmpllist; tp != NULL; tp = nexttp ) {
+	    nexttp = tp->dt_next;
+	    free_disptmpl( tp );
+	}
+    }
+}
+
+
+static void
+free_disptmpl( struct ldap_disptmpl *tmpl )
+{
+    if ( tmpl != NULL ) {
+	if ( tmpl->dt_name != NULL ) {
+	    NSLDAPI_FREE(  tmpl->dt_name );
+	}
+
+	if ( tmpl->dt_pluralname != NULL ) {
+	    NSLDAPI_FREE( tmpl->dt_pluralname );
+	}
+
+	if ( tmpl->dt_iconname != NULL ) {
+	    NSLDAPI_FREE( tmpl->dt_iconname );
+	}
+
+	if ( tmpl->dt_authattrname != NULL ) {
+	    NSLDAPI_FREE( tmpl->dt_authattrname );
+	}
+
+	if ( tmpl->dt_defrdnattrname != NULL ) {
+	    NSLDAPI_FREE( tmpl->dt_defrdnattrname );
+	}
+
+	if ( tmpl->dt_defaddlocation != NULL ) {
+	    NSLDAPI_FREE( tmpl->dt_defaddlocation );
+	}
+
+	if (  tmpl->dt_oclist != NULL ) {
+	    struct ldap_oclist	*ocp, *nextocp;
+
+	    for ( ocp = tmpl->dt_oclist; ocp != NULL; ocp = nextocp ) {
+		nextocp = ocp->oc_next;
+		nsldapi_free_strarray( ocp->oc_objclasses );
+		NSLDAPI_FREE( ocp );
+	    }
+	}
+
+	if (  tmpl->dt_adddeflist != NULL ) {
+	    struct ldap_adddeflist	*adp, *nextadp;
+
+	    for ( adp = tmpl->dt_adddeflist; adp != NULL; adp = nextadp ) {
+		nextadp = adp->ad_next;
+		if( adp->ad_attrname != NULL ) {
+		    NSLDAPI_FREE( adp->ad_attrname );
+		}
+		if( adp->ad_value != NULL ) {
+		    NSLDAPI_FREE( adp->ad_value );
+		}
+		NSLDAPI_FREE( adp );
+	    }
+	}
+
+	if (  tmpl->dt_items != NULL ) {
+	    struct ldap_tmplitem	*rowp, *nextrowp, *colp, *nextcolp;
+
+	    for ( rowp = tmpl->dt_items; rowp != NULL; rowp = nextrowp ) {
+		nextrowp = rowp->ti_next_in_col;
+		for ( colp = rowp; colp != NULL; colp = nextcolp ) {
+		    nextcolp = colp->ti_next_in_row;
+		    if ( colp->ti_attrname != NULL ) {
+			NSLDAPI_FREE( colp->ti_attrname );
+		    }
+		    if ( colp->ti_label != NULL ) {
+			NSLDAPI_FREE( colp->ti_label );
+		    }
+		    if ( colp->ti_args != NULL ) {
+			nsldapi_free_strarray( colp->ti_args );
+		    }
+		    NSLDAPI_FREE( colp );
+		}
+	    }
+	}
+
+	NSLDAPI_FREE( tmpl );
+    }
+}
+
+
+struct ldap_disptmpl *
+LDAP_CALL
+ldap_first_disptmpl( struct ldap_disptmpl *tmpllist )
+{
+    return( tmpllist );
+}
+
+
+struct ldap_disptmpl *
+LDAP_CALL
+ldap_next_disptmpl( struct ldap_disptmpl *tmpllist,
+	struct ldap_disptmpl *tmpl )
+{
+    return( tmpl == NULLDISPTMPL ? tmpl : tmpl->dt_next );
+}
+
+
+struct ldap_disptmpl *
+LDAP_CALL
+ldap_name2template( char *name, struct ldap_disptmpl *tmpllist )
+{
+    struct ldap_disptmpl	*dtp;
+
+    for ( dtp = ldap_first_disptmpl( tmpllist ); dtp != NULLDISPTMPL;
+	    dtp = ldap_next_disptmpl( tmpllist, dtp )) {
+	if ( strcasecmp( name, dtp->dt_name ) == 0 ) {
+	    return( dtp );
+	}
+    }
+
+    return( NULLDISPTMPL );
+}
+
+
+struct ldap_disptmpl *
+LDAP_CALL
+ldap_oc2template( char **oclist, struct ldap_disptmpl *tmpllist )
+{
+    struct ldap_disptmpl	*dtp;
+    struct ldap_oclist		*oclp;
+    int				i, j, needcnt, matchcnt;
+
+    if ( tmpllist == NULL || oclist == NULL || oclist[ 0 ] == NULL ) {
+	return( NULLDISPTMPL );
+    }
+
+    for ( dtp = ldap_first_disptmpl( tmpllist ); dtp != NULLDISPTMPL;
+		dtp = ldap_next_disptmpl( tmpllist, dtp )) {
+	for ( oclp = dtp->dt_oclist; oclp != NULLOCLIST;
+		oclp = oclp->oc_next ) {
+	    needcnt = matchcnt = 0;
+	    for ( i = 0; oclp->oc_objclasses[ i ] != NULL; ++i ) {
+		for ( j = 0; oclist[ j ] != NULL; ++j ) {
+		    if ( strcasecmp( oclist[ j ], oclp->oc_objclasses[ i ] )
+			    == 0 ) {
+			++matchcnt;
+		    }
+		}
+		++needcnt;
+	    }
+
+	    if ( matchcnt == needcnt ) {
+		return( dtp );
+	    }
+	}
+    }
+
+    return( NULLDISPTMPL );
+}
+
+
+struct ldap_tmplitem *
+LDAP_CALL
+ldap_first_tmplrow( struct ldap_disptmpl *tmpl )
+{
+    return( tmpl->dt_items );
+}
+
+
+struct ldap_tmplitem *
+LDAP_CALL
+ldap_next_tmplrow( struct ldap_disptmpl *tmpl, struct ldap_tmplitem *row )
+{
+    return( row == NULLTMPLITEM ? row : row->ti_next_in_col );
+}
+
+
+struct ldap_tmplitem *
+LDAP_CALL
+ldap_first_tmplcol( struct ldap_disptmpl *tmpl, struct ldap_tmplitem *row )
+{
+    return( row );
+}
+
+
+struct ldap_tmplitem *
+LDAP_CALL
+ldap_next_tmplcol( struct ldap_disptmpl *tmpl, struct ldap_tmplitem *row,
+	struct ldap_tmplitem *col )
+{
+    return( col == NULLTMPLITEM ? col : col->ti_next_in_row );
+}
+
+
+char **
+LDAP_CALL
+ldap_tmplattrs( struct ldap_disptmpl *tmpl, char **includeattrs,
+	int exclude, unsigned long syntaxmask )
+{
+/*
+ * this routine should filter out duplicate attributes...
+ */
+    struct ldap_tmplitem	*tirowp, *ticolp;
+    int			i, attrcnt, memerr;
+    char		**attrs;
+
+    attrcnt = 0;
+    memerr = 0;
+
+    if (( attrs = (char **)NSLDAPI_MALLOC( sizeof( char * ))) == NULL ) {
+	return( NULL );
+    }
+
+    if ( includeattrs != NULL ) {
+	for ( i = 0; !memerr && includeattrs[ i ] != NULL; ++i ) {
+	    if (( attrs = (char **)NSLDAPI_REALLOC( attrs, ( attrcnt + 2 ) *
+		    sizeof( char * ))) == NULL || ( attrs[ attrcnt++ ] =
+		    nsldapi_strdup( includeattrs[ i ] )) == NULL ) {
+		memerr = 1;
+	    } else {
+		attrs[ attrcnt ] = NULL;
+	    }
+	}
+    }
+
+    for ( tirowp = ldap_first_tmplrow( tmpl );
+	    !memerr && tirowp != NULLTMPLITEM;
+	    tirowp = ldap_next_tmplrow( tmpl, tirowp )) {
+	for ( ticolp = ldap_first_tmplcol( tmpl, tirowp );
+		ticolp != NULLTMPLITEM;
+		ticolp = ldap_next_tmplcol( tmpl, tirowp, ticolp )) {
+
+	    if ( syntaxmask != 0 ) {
+		if (( exclude &&
+			( syntaxmask & ticolp->ti_syntaxid ) != 0 ) ||
+			( !exclude &&
+			( syntaxmask & ticolp->ti_syntaxid ) == 0 )) {
+		    continue;
+		}
+	    }
+
+	    if ( ticolp->ti_attrname != NULL ) {
+		if (( attrs = (char **)NSLDAPI_REALLOC( attrs, ( attrcnt + 2 )
+			* sizeof( char * ))) == NULL || ( attrs[ attrcnt++ ] =
+			nsldapi_strdup( ticolp->ti_attrname )) == NULL ) {
+		    memerr = 1;
+		} else {
+		    attrs[ attrcnt ] = NULL;
+		}
+	    }
+	}
+    }
+
+    if ( memerr || attrcnt == 0 ) {
+	for ( i = 0; i < attrcnt; ++i ) {
+	    if ( attrs[ i ] != NULL ) {
+		NSLDAPI_FREE( attrs[ i ] );
+	    }
+	}
+
+	NSLDAPI_FREE( (char *)attrs );
+	return( NULL );
+    }
+
+    return( attrs );
+}
+
+
+static int
+read_next_tmpl( char **bufp, long *blenp, struct ldap_disptmpl **tmplp,
+	int dtversion )
+{
+    int				i, j, tokcnt, samerow, adsource;
+    char			**toks, *itemopts;
+    struct ldap_disptmpl	*tmpl = NULL;
+    struct ldap_oclist		*ocp = NULL, *prevocp = NULL;
+    struct ldap_adddeflist	*adp = NULL, *prevadp = NULL;
+    struct ldap_tmplitem	*rowp = NULL, *ip = NULL, *previp = NULL;
+
+    /*
+     * template name comes first
+     */
+    if (( tokcnt = nsldapi_next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+	nsldapi_free_strarray( toks );
+	return( tokcnt == 0 ? 0 : LDAP_TMPL_ERR_SYNTAX );
+    }
+
+    if (( tmpl = (struct ldap_disptmpl *)NSLDAPI_CALLOC( 1,
+	    sizeof( struct ldap_disptmpl ))) == NULL ) {
+	nsldapi_free_strarray( toks );
+	return(  LDAP_TMPL_ERR_MEM );
+    }
+    tmpl->dt_name = toks[ 0 ];
+    NSLDAPI_FREE( (char *)toks );
+
+    /*
+     * template plural name comes next
+     */
+    if (( tokcnt = nsldapi_next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+	nsldapi_free_strarray( toks );
+	free_disptmpl( tmpl );
+	return( LDAP_TMPL_ERR_SYNTAX );
+    }
+    tmpl->dt_pluralname = toks[ 0 ];
+    NSLDAPI_FREE( (char *)toks );
+
+    /*
+     * template icon name is next
+     */
+    if (( tokcnt = nsldapi_next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+	nsldapi_free_strarray( toks );
+	free_disptmpl( tmpl );
+	return( LDAP_TMPL_ERR_SYNTAX );
+    }
+    tmpl->dt_iconname = toks[ 0 ];
+    NSLDAPI_FREE( (char *)toks );
+
+    /*
+     * template options come next
+     */
+    if (( tokcnt = nsldapi_next_line_tokens( bufp, blenp, &toks )) < 1 ) {
+	nsldapi_free_strarray( toks );
+	free_disptmpl( tmpl );
+	return( LDAP_TMPL_ERR_SYNTAX );
+    }
+    for ( i = 0; toks[ i ] != NULL; ++i ) {
+	for ( j = 0; tmploptions[ j ] != NULL; ++j ) {
+	    if ( strcasecmp( toks[ i ], tmploptions[ j ] ) == 0 ) {
+		tmpl->dt_options |= tmploptvals[ j ];
+	    }
+	}
+    }
+    nsldapi_free_strarray( toks );
+
+    /*
+     * object class list is next
+     */
+    while (( tokcnt = nsldapi_next_line_tokens( bufp, blenp, &toks )) > 0 ) {
+	if (( ocp = (struct ldap_oclist *)NSLDAPI_CALLOC( 1,
+		sizeof( struct ldap_oclist ))) == NULL ) {
+	    nsldapi_free_strarray( toks );
+	    free_disptmpl( tmpl );
+	    return( LDAP_TMPL_ERR_MEM );
+	}
+	ocp->oc_objclasses = toks;
+	if ( tmpl->dt_oclist == NULL ) {
+	    tmpl->dt_oclist = ocp;
+	} else {
+	    prevocp->oc_next = ocp;
+	}
+	prevocp = ocp;
+    }
+    if ( tokcnt < 0 ) {
+	free_disptmpl( tmpl );
+	return( LDAP_TMPL_ERR_SYNTAX );
+    }
+
+    /*
+     * read name of attribute to authenticate as
+     */
+    if (( tokcnt = nsldapi_next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+	nsldapi_free_strarray( toks );
+	free_disptmpl( tmpl );
+	return( LDAP_TMPL_ERR_SYNTAX );
+    }
+    if ( toks[ 0 ][ 0 ] != '\0' ) {
+	tmpl->dt_authattrname = toks[ 0 ];
+    } else {
+	NSLDAPI_FREE( toks[ 0 ] );
+    }
+    NSLDAPI_FREE( (char *)toks );
+
+    /*
+     * read default attribute to use for RDN
+     */
+    if (( tokcnt = nsldapi_next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+	nsldapi_free_strarray( toks );
+	free_disptmpl( tmpl );
+	return( LDAP_TMPL_ERR_SYNTAX );
+    }
+    tmpl->dt_defrdnattrname = toks[ 0 ];
+    NSLDAPI_FREE( (char *)toks );
+
+    /*
+     * read default location for new entries
+     */
+    if (( tokcnt = nsldapi_next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+	nsldapi_free_strarray( toks );
+	free_disptmpl( tmpl );
+	return( LDAP_TMPL_ERR_SYNTAX );
+    }
+    if ( toks[ 0 ][ 0 ] != '\0' ) {
+	tmpl->dt_defaddlocation = toks[ 0 ];
+    } else {
+	NSLDAPI_FREE( toks[ 0 ] );
+    }
+    NSLDAPI_FREE( (char *)toks );
+
+    /*
+     * read list of rules used to define default values for new entries
+     */
+    while (( tokcnt = nsldapi_next_line_tokens( bufp, blenp, &toks )) > 0 ) {
+	if ( strcasecmp( ADDEF_CONSTANT, toks[ 0 ] ) == 0 ) {
+	    adsource = LDAP_ADSRC_CONSTANTVALUE;
+	} else if ( strcasecmp( ADDEF_ADDERSDN, toks[ 0 ] ) == 0 ) {
+	    adsource = LDAP_ADSRC_ADDERSDN;
+	} else {
+	    adsource = 0;
+	}
+	if ( adsource == 0 || tokcnt < 2 ||
+		( adsource == LDAP_ADSRC_CONSTANTVALUE && tokcnt != 3 ) ||
+		( adsource == LDAP_ADSRC_ADDERSDN && tokcnt != 2 )) {
+	    nsldapi_free_strarray( toks );
+	    free_disptmpl( tmpl );
+	    return( LDAP_TMPL_ERR_SYNTAX );
+	}
+		
+	if (( adp = (struct ldap_adddeflist *)NSLDAPI_CALLOC( 1,
+		sizeof( struct ldap_adddeflist ))) == NULL ) {
+	    nsldapi_free_strarray( toks );
+	    free_disptmpl( tmpl );
+	    return( LDAP_TMPL_ERR_MEM );
+	}
+	adp->ad_source = adsource;
+	adp->ad_attrname = toks[ 1 ];
+	if ( adsource == LDAP_ADSRC_CONSTANTVALUE ) {
+	    adp->ad_value = toks[ 2 ];
+	}
+	NSLDAPI_FREE( toks[ 0 ] );
+	NSLDAPI_FREE( (char *)toks );
+
+	if ( tmpl->dt_adddeflist == NULL ) {
+	    tmpl->dt_adddeflist = adp;
+	} else {
+	    prevadp->ad_next = adp;
+	}
+	prevadp = adp;
+    }
+
+    /*
+     * item list is next
+     */
+    samerow = 0;
+    while (( tokcnt = nsldapi_next_line_tokens( bufp, blenp, &toks )) > 0 ) {
+	if ( strcasecmp( toks[ 0 ], "item" ) == 0 ) {
+	    if ( tokcnt < 4 ) {
+		nsldapi_free_strarray( toks );
+		free_disptmpl( tmpl );
+		return( LDAP_TMPL_ERR_SYNTAX );
+	    }
+
+	    if (( ip = (struct ldap_tmplitem *)NSLDAPI_CALLOC( 1,
+		    sizeof( struct ldap_tmplitem ))) == NULL ) {
+		nsldapi_free_strarray( toks );
+		free_disptmpl( tmpl );
+		return( LDAP_TMPL_ERR_MEM );
+	    }
+
+	    /*
+	     * find syntaxid from config file string
+	     */
+	    while (( itemopts = strrchr( toks[ 1 ], ',' )) != NULL ) {
+		*itemopts++ = '\0';
+		for ( i = 0; itemoptions[ i ] != NULL; ++i ) {
+		    if ( strcasecmp( itemopts, itemoptions[ i ] ) == 0 ) {
+			break;
+		    }
+		}
+		if ( itemoptions[ i ] == NULL ) {
+		    nsldapi_free_strarray( toks );
+		    free_disptmpl( tmpl );
+		    return( LDAP_TMPL_ERR_SYNTAX );
+		}
+		ip->ti_options |= itemoptvals[ i ];
+	    }
+
+	    for ( i = 0; itemtypes[ i ] != NULL; ++i ) {
+		if ( strcasecmp( toks[ 1 ], itemtypes[ i ] ) == 0 ) {
+		    break;
+		}
+	    }
+	    if ( itemtypes[ i ] == NULL ) {
+		nsldapi_free_strarray( toks );
+		free_disptmpl( tmpl );
+		return( LDAP_TMPL_ERR_SYNTAX );
+	    }
+
+	    NSLDAPI_FREE( toks[ 0 ] );
+	    NSLDAPI_FREE( toks[ 1 ] );
+	    ip->ti_syntaxid = itemsynids[ i ];
+	    ip->ti_label = toks[ 2 ];
+	    if ( toks[ 3 ][ 0 ] == '\0' ) {
+		ip->ti_attrname = NULL;
+		NSLDAPI_FREE( toks[ 3 ] );
+	    } else {
+		ip->ti_attrname = toks[ 3 ];
+	    }
+	    if ( toks[ 4 ] != NULL ) {	/* extra args. */
+		for ( i = 0; toks[ i + 4 ] != NULL; ++i ) {
+		    ;
+		}
+		if (( ip->ti_args = (char **)NSLDAPI_CALLOC( i + 1,
+			sizeof( char * ))) == NULL ) {
+		    free_disptmpl( tmpl );
+		    return( LDAP_TMPL_ERR_MEM );
+		}
+		for ( i = 0; toks[ i + 4 ] != NULL; ++i ) {
+		    ip->ti_args[ i ] = toks[ i + 4 ];
+		}
+	    }
+	    NSLDAPI_FREE( (char *)toks );
+
+	    if ( tmpl->dt_items == NULL ) {
+		tmpl->dt_items = rowp = ip;
+	    } else if ( samerow ) {
+		previp->ti_next_in_row = ip;
+	    } else {
+		rowp->ti_next_in_col = ip;
+		rowp = ip;
+	    }
+	    previp = ip;
+	    samerow = 0;
+	} else if ( strcasecmp( toks[ 0 ], "samerow" ) == 0 ) {
+	    nsldapi_free_strarray( toks );
+	    samerow = 1;
+	} else {
+	    nsldapi_free_strarray( toks );
+	    free_disptmpl( tmpl );
+	    return( LDAP_TMPL_ERR_SYNTAX );
+	}
+    }
+    if ( tokcnt < 0 ) {
+	free_disptmpl( tmpl );
+	return( LDAP_TMPL_ERR_SYNTAX );
+    }
+
+    *tmplp = tmpl;
+    return( 0 );
+}
+
+
+struct tmplerror {
+	int	e_code;
+	char	*e_reason;
+};
+
+static struct tmplerror ldap_tmplerrlist[] = {
+	{ LDAP_TMPL_ERR_VERSION, "Bad template version"		},
+	{ LDAP_TMPL_ERR_MEM,     "Out of memory"		}, 
+	{ LDAP_TMPL_ERR_SYNTAX,  "Bad template syntax"		},
+	{ LDAP_TMPL_ERR_FILE,    "File error reading template"	},
+	{ -1, 0 }
+};
+
+char *
+LDAP_CALL
+ldap_tmplerr2string( int err )
+{
+	int	i;
+
+	for ( i = 0; ldap_tmplerrlist[i].e_code != -1; i++ ) {
+		if ( err == ldap_tmplerrlist[i].e_code )
+			return( ldap_tmplerrlist[i].e_reason );
+	}
+
+	return( "Unknown error" );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/dllmain.c
@@ -0,0 +1,178 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ * Microsoft Windows specifics for LIBLDAP DLL
+ */
+#include "ldap.h"
+#include "lber.h"
+
+
+#ifdef _WIN32
+/* Lifted from Q125688
+ * How to Port a 16-bit DLL to a Win32 DLL
+ * on the MSVC 4.0 CD
+ */
+BOOL WINAPI DllMain (HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
+{
+	switch (fdwReason)
+	{
+	case DLL_PROCESS_ATTACH:
+		 /* Code from LibMain inserted here.  Return TRUE to keep the
+		    DLL loaded or return FALSE to fail loading the DLL.
+
+		    You may have to modify the code in your original LibMain to
+		    account for the fact that it may be called more than once.
+		    You will get one DLL_PROCESS_ATTACH for each process that
+		    loads the DLL. This is different from LibMain which gets
+		    called only once when the DLL is loaded. The only time this
+		    is critical is when you are using shared data sections.
+		    If you are using shared data sections for statically
+		    allocated data, you will need to be careful to initialize it
+		    only once. Check your code carefully.
+
+		    Certain one-time initializations may now need to be done for
+		    each process that attaches. You may also not need code from
+		    your original LibMain because the operating system may now
+		    be doing it for you.
+		 */
+		/*
+		 * 16 bit code calls UnlockData()
+		 * which is mapped to UnlockSegment in windows.h
+		 * in 32 bit world UnlockData is not defined anywhere
+		 * UnlockSegment is mapped to GlobalUnfix in winbase.h
+		 * and the docs for both UnlockSegment and GlobalUnfix say 
+		 * ".. function is oboslete.  Segments have no meaning 
+		 *  in the 32-bit environment".  So we do nothing here.
+		 */
+		/* If we are building a version that includes the security libraries,
+		 * we have to initialize Winsock here. If not, we can defer until the
+		 * first real socket call is made (in mozock.c).
+		 */
+#ifdef LINK_SSL
+	{
+		WSADATA wsaData;
+		WSAStartup(0x0101, &wsaData);
+	}
+#endif
+
+		break;
+
+	case DLL_THREAD_ATTACH:
+		/* Called each time a thread is created in a process that has
+		   already loaded (attached to) this DLL. Does not get called
+		   for each thread that exists in the process before it loaded
+		   the DLL.
+
+		   Do thread-specific initialization here.
+		*/
+		break;
+
+	case DLL_THREAD_DETACH:
+		/* Same as above, but called when a thread in the process
+		   exits.
+
+		   Do thread-specific cleanup here.
+		*/
+		break;
+
+	case DLL_PROCESS_DETACH:
+		/* Code from _WEP inserted here.  This code may (like the
+		   LibMain) not be necessary.  Check to make certain that the
+		   operating system is not doing it for you.
+		*/
+#ifdef LINK_SSL
+		WSACleanup();
+#endif
+
+		break;
+	}
+	/* The return value is only used for DLL_PROCESS_ATTACH; all other
+	conditions are ignored.  */
+	return TRUE;   // successful DLL_PROCESS_ATTACH
+}
+#else
+int CALLBACK
+LibMain( HINSTANCE hinst, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine )
+{
+	/*UnlockData( 0 );*/
+ 	return( 1 );
+}
+
+BOOL CALLBACK __loadds WEP(BOOL fSystemExit)
+{
+	WSACleanup();
+    return TRUE;
+}
+
+#endif
+
+#ifdef LDAP_DEBUG
+#ifndef _WIN32
+#include <stdarg.h>
+#include <stdio.h>
+
+void LDAP_C LDAPDebug( int level, char* fmt, ... )
+{
+	static char debugBuf[1024];
+
+	if (ldap_debug & level)
+	{
+		va_list ap;
+		va_start (ap, fmt);
+		_snprintf (debugBuf, sizeof(debugBuf), fmt, ap);
+		va_end (ap);
+
+		OutputDebugString (debugBuf);
+	}
+}
+#endif
+#endif
+
+#ifndef _WIN32
+
+/* The 16-bit version of the RTL does not implement perror() */
+
+#include <stdio.h>
+
+void perror( const char *msg )
+{
+	char buf[128];
+	wsprintf( buf, "%s: error %d\n", msg, WSAGetLastError()) ;
+	OutputDebugString( buf );
+}
+
+#endif
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/dsparse.c
@@ -0,0 +1,227 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ * Copyright (c) 1993, 1994 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+/*
+ * dsparse.c:  parsing routines used by display template and search 
+ * preference file library routines for LDAP clients.
+ *
+ */
+
+#include "ldap-int.h"
+
+static int next_line( char **bufp, long *blenp, char **linep );
+static char *next_token( char ** sp );
+
+int
+nsldapi_next_line_tokens( char **bufp, long *blenp, char ***toksp )
+{
+    char	*p, *line, *token, **toks;
+    int		rc, tokcnt;
+
+    *toksp = NULL;
+
+    if (( rc = next_line( bufp, blenp, &line )) <= 0 ) {
+	return( rc );
+    }
+
+    if (( toks = (char **)NSLDAPI_CALLOC( 1, sizeof( char * ))) == NULL ) {
+	NSLDAPI_FREE( line );
+	return( -1 );
+    }
+    tokcnt = 0;
+
+    p = line;
+    while (( token = next_token( &p )) != NULL ) {
+	if (( toks = (char **)NSLDAPI_REALLOC( toks, ( tokcnt + 2 ) *
+		sizeof( char * ))) == NULL ) {
+	    NSLDAPI_FREE( (char *)toks );
+	    NSLDAPI_FREE( line );
+	    return( -1 );
+	}
+	toks[ tokcnt ] = token;
+	toks[ ++tokcnt ] = NULL;
+    }
+
+    if ( tokcnt == 1 && strcasecmp( toks[ 0 ], "END" ) == 0 ) {
+	tokcnt = 0;
+	nsldapi_free_strarray( toks );
+	toks = NULL;
+    }
+
+    NSLDAPI_FREE( line );
+
+    if ( tokcnt == 0 ) {
+	if ( toks != NULL ) {
+	    NSLDAPI_FREE( (char *)toks );
+	}
+    } else {
+	*toksp = toks;
+    }
+
+    return( tokcnt );
+}
+
+
+static int
+next_line( char **bufp, long *blenp, char **linep )
+{
+    char	*linestart, *line, *p;
+    long	plen;
+
+    linestart = *bufp;
+    p = *bufp;
+    plen = *blenp;
+
+    do {
+	for ( linestart = p; plen > 0; ++p, --plen ) {
+	    if ( *p == '\r' ) {
+		if ( plen > 1 && *(p+1) == '\n' ) {
+		    ++p;
+		    --plen;
+		}
+		break;
+	    }
+
+	    if ( *p == '\n' ) {
+		if ( plen > 1 && *(p+1) == '\r' ) {
+		    ++p;
+		    --plen;
+		}
+		break;
+	    }
+	}
+	++p;
+	--plen;
+    } while ( plen > 0 && ( *linestart == '#' || linestart + 1 == p ));
+
+
+    *bufp = p;
+    *blenp = plen;
+
+
+    if ( plen <= 0 ) {
+	*linep = NULL;
+	return( 0 );	/* end of file */
+    }
+
+    if (( line = NSLDAPI_MALLOC( p - linestart )) == NULL ) {
+	*linep = NULL;
+	return( -1 );	/* fatal error */
+    }
+
+    SAFEMEMCPY( line, linestart, p - linestart );
+    line[ p - linestart - 1 ] = '\0';
+    *linep = line;
+    return( strlen( line ));
+}
+
+
+static char *
+next_token( char **sp )
+{
+    int		in_quote = 0;
+    char	*p, *tokstart, *t;
+
+    if ( **sp == '\0' ) {
+	return( NULL );
+    }
+
+    p = *sp;
+
+    while ( ldap_utf8isspace( p )) {		/* skip leading white space */
+	++p;
+    }
+
+    if ( *p == '\0' ) {
+	return( NULL );
+    }
+
+    if ( *p == '\"' ) {
+	in_quote = 1;
+	++p;
+    }
+    t = tokstart = p;
+
+    for ( ;; ) {
+	if ( *p == '\0' || ( ldap_utf8isspace( p ) && !in_quote )) {
+	    if ( *p != '\0' ) {
+		++p;
+	    }
+	    *t++ = '\0';		/* end of token */
+	    break;
+	}
+
+	if ( *p == '\"' ) {
+	    in_quote = !in_quote;
+	    ++p;
+	} else {
+	    *t++ = *p++;
+	}
+    }
+
+    *sp = p;
+
+    if ( t == tokstart ) {
+	return( NULL );
+    }
+
+    return( nsldapi_strdup( tokstart ));
+}
+
+
+void
+nsldapi_free_strarray( char **sap )
+{
+    int		i;
+
+    if ( sap != NULL ) {
+	for ( i = 0; sap[ i ] != NULL; ++i ) {
+	    NSLDAPI_FREE( sap[ i ] );
+	}
+	NSLDAPI_FREE( (char *)sap );
+    }
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/error.c
@@ -0,0 +1,490 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+#include "ldap-int.h"
+
+struct ldaperror {
+	int	e_code;
+	char	*e_reason;
+};
+
+static struct ldaperror ldap_errlist[] = {
+	{ LDAP_SUCCESS, 			"Success" },
+	{ LDAP_OPERATIONS_ERROR, 		"Operations error" },
+	{ LDAP_PROTOCOL_ERROR, 			"Protocol error" },
+	{ LDAP_TIMELIMIT_EXCEEDED,		"Timelimit exceeded" },
+	{ LDAP_SIZELIMIT_EXCEEDED, 		"Sizelimit exceeded" },
+	{ LDAP_COMPARE_FALSE, 			"Compare false" },
+	{ LDAP_COMPARE_TRUE, 			"Compare true" },
+	{ LDAP_STRONG_AUTH_NOT_SUPPORTED,	"Authentication method not supported" },
+	{ LDAP_STRONG_AUTH_REQUIRED, 		"Strong authentication required" },
+	{ LDAP_PARTIAL_RESULTS, 		"Partial results and referral received" },
+	{ LDAP_REFERRAL, 			"Referral received" },
+	{ LDAP_ADMINLIMIT_EXCEEDED,		"Administrative limit exceeded" },
+	{ LDAP_UNAVAILABLE_CRITICAL_EXTENSION,	"Unavailable critical extension" },
+	{ LDAP_CONFIDENTIALITY_REQUIRED,	"Confidentiality required" },
+	{ LDAP_SASL_BIND_IN_PROGRESS,		"SASL bind in progress" },
+
+	{ LDAP_NO_SUCH_ATTRIBUTE, 		"No such attribute" },
+	{ LDAP_UNDEFINED_TYPE, 			"Undefined attribute type" },
+	{ LDAP_INAPPROPRIATE_MATCHING, 		"Inappropriate matching" },
+	{ LDAP_CONSTRAINT_VIOLATION, 		"Constraint violation" },
+	{ LDAP_TYPE_OR_VALUE_EXISTS, 		"Type or value exists" },
+	{ LDAP_INVALID_SYNTAX, 			"Invalid syntax" },
+
+	{ LDAP_NO_SUCH_OBJECT, 			"No such object" },
+	{ LDAP_ALIAS_PROBLEM, 			"Alias problem" },
+	{ LDAP_INVALID_DN_SYNTAX,		"Invalid DN syntax" },
+	{ LDAP_IS_LEAF, 			"Object is a leaf" },
+	{ LDAP_ALIAS_DEREF_PROBLEM, 		"Alias dereferencing problem" },
+
+	{ LDAP_INAPPROPRIATE_AUTH, 		"Inappropriate authentication" },
+	{ LDAP_INVALID_CREDENTIALS, 		"Invalid credentials" },
+	{ LDAP_INSUFFICIENT_ACCESS, 		"Insufficient access" },
+	{ LDAP_BUSY, 				"DSA is busy" },
+	{ LDAP_UNAVAILABLE, 			"DSA is unavailable" },
+	{ LDAP_UNWILLING_TO_PERFORM, 		"DSA is unwilling to perform" },
+	{ LDAP_LOOP_DETECT, 			"Loop detected" },
+    { LDAP_SORT_CONTROL_MISSING,    "Sort Control is missing"  },
+    { LDAP_INDEX_RANGE_ERROR,              "Search results exceed the range specified by the offsets" }, 
+    
+    { LDAP_NAMING_VIOLATION, 		"Naming violation" },
+	{ LDAP_OBJECT_CLASS_VIOLATION, 		"Object class violation" },
+	{ LDAP_NOT_ALLOWED_ON_NONLEAF, 		"Operation not allowed on nonleaf" },
+	{ LDAP_NOT_ALLOWED_ON_RDN, 		"Operation not allowed on RDN" },
+	{ LDAP_ALREADY_EXISTS, 			"Already exists" },
+	{ LDAP_NO_OBJECT_CLASS_MODS, 		"Cannot modify object class" },
+	{ LDAP_RESULTS_TOO_LARGE,		"Results too large" },
+	{ LDAP_AFFECTS_MULTIPLE_DSAS,		"Affects multiple servers" },
+
+	{ LDAP_OTHER, 				"Unknown error" },
+	{ LDAP_SERVER_DOWN,			"Can't contact LDAP server" },
+	{ LDAP_LOCAL_ERROR,			"Local error" },
+	{ LDAP_ENCODING_ERROR,			"Encoding error" },
+	{ LDAP_DECODING_ERROR,			"Decoding error" },
+	{ LDAP_TIMEOUT,				"Timed out" },
+	{ LDAP_AUTH_UNKNOWN,			"Unknown authentication method" },
+	{ LDAP_FILTER_ERROR,			"Bad search filter" },
+	{ LDAP_USER_CANCELLED,			"User cancelled operation" },
+	{ LDAP_PARAM_ERROR,			"Bad parameter to an ldap routine" },
+	{ LDAP_NO_MEMORY,			"Out of memory" },
+	{ LDAP_CONNECT_ERROR,			"Can't connect to the LDAP server" },
+	{ LDAP_NOT_SUPPORTED,			"Not supported by this version of the LDAP protocol" },
+	{ LDAP_CONTROL_NOT_FOUND,		"Requested LDAP control not found" },
+	{ LDAP_NO_RESULTS_RETURNED,		"No results returned" },
+	{ LDAP_MORE_RESULTS_TO_RETURN,		"More results to return" },
+	{ LDAP_CLIENT_LOOP,			"Client detected loop" },
+	{ LDAP_REFERRAL_LIMIT_EXCEEDED,		"Referral hop limit exceeded" },
+	{ -1, 0 }
+};
+
+char *
+LDAP_CALL
+ldap_err2string( int err )
+{
+	int	i;
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_err2string\n", 0, 0, 0 );
+
+	for ( i = 0; ldap_errlist[i].e_code != -1; i++ ) {
+		if ( err == ldap_errlist[i].e_code )
+			return( ldap_errlist[i].e_reason );
+	}
+
+	return( "Unknown error" );
+}
+
+
+static char *
+nsldapi_safe_strerror( int e )
+{
+	char *s;
+
+	if (( s = strerror( e )) == NULL ) {
+		s = "unknown error";
+	}
+
+	return( s );
+}
+
+
+void
+LDAP_CALL
+ldap_perror( LDAP *ld, const char *s )
+{
+	int		i, err;
+	char	*matched = NULL;
+	char	*errmsg = NULL; 
+	char	*separator;
+	char    msg[1024];
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_perror\n", 0, 0, 0 );
+
+	if ( s == NULL ) {
+		s = separator = "";
+	} else {
+		separator = ": ";
+	}
+
+	if ( ld == NULL ) {
+		snprintf( msg, sizeof( msg ), 
+			"%s%s%s", s, separator, nsldapi_safe_strerror( errno ) );
+		ber_err_print( msg );
+		return;
+	}
+
+	LDAP_MUTEX_LOCK( ld, LDAP_ERR_LOCK );
+	err = LDAP_GET_LDERRNO( ld, &matched, &errmsg );
+	for ( i = 0; ldap_errlist[i].e_code != -1; i++ ) {
+		if ( err == ldap_errlist[i].e_code ) {
+			snprintf( msg, sizeof( msg ), 
+				"%s%s%s", s, separator, ldap_errlist[i].e_reason );
+			ber_err_print( msg );
+			if ( err == LDAP_CONNECT_ERROR ) {
+				ber_err_print( " - " );
+				ber_err_print( nsldapi_safe_strerror(
+				    LDAP_GET_ERRNO( ld )));
+			}
+			ber_err_print( "\n" );
+			if ( matched != NULL && *matched != '\0' ) {
+				snprintf( msg, sizeof( msg ), 
+					"%s%smatched: %s\n", s, separator, matched );
+				ber_err_print( msg );
+			}
+			if ( errmsg != NULL && *errmsg != '\0' ) {
+				snprintf( msg, sizeof( msg ), 
+					"%s%sadditional info: %s\n", s, separator, errmsg );
+				ber_err_print( msg );
+			}
+			LDAP_MUTEX_UNLOCK( ld, LDAP_ERR_LOCK );
+			return;
+		}
+	}
+	snprintf( msg, sizeof( msg ), 
+		"%s%sNot an LDAP errno %d\n", s, separator, err );
+	ber_err_print( msg );
+	LDAP_MUTEX_UNLOCK( ld, LDAP_ERR_LOCK );
+}
+
+int
+LDAP_CALL
+ldap_result2error( LDAP *ld, LDAPMessage *r, int freeit )
+{
+	int	lderr_parse, lderr;
+
+	lderr_parse = ldap_parse_result( ld, r, &lderr, NULL, NULL, NULL,
+	    NULL, freeit );
+
+	if ( lderr_parse != LDAP_SUCCESS ) {
+		return( lderr_parse );
+	}
+
+	return( lderr );
+}
+
+int
+LDAP_CALL
+ldap_get_lderrno( LDAP *ld, char **m, char **s )
+{
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( LDAP_PARAM_ERROR );	/* punt */
+	}
+
+	if ( ld->ld_get_lderrno_fn == NULL ) {
+		if ( m != NULL ) {
+			*m = ld->ld_matched;
+		}
+		if ( s != NULL ) {
+			*s = ld->ld_error;
+		}
+		return( ld->ld_errno );
+	} else {
+		return( ld->ld_get_lderrno_fn( m, s, ld->ld_lderrno_arg ) );
+	}
+}
+
+
+/*
+ * Note: there is no need for callers of ldap_set_lderrno() to lock the
+ * ld mutex.  If applications intend to share an LDAP session handle
+ * between threads they *must* perform their own locking around the
+ * session handle or they must install a "set lderrno" thread callback
+ * function.
+ * 
+ */
+int
+LDAP_CALL
+ldap_set_lderrno( LDAP *ld, int e, char *m, char *s )
+{
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( LDAP_PARAM_ERROR );
+	}
+
+	if ( ld->ld_set_lderrno_fn != NULL ) {
+		ld->ld_set_lderrno_fn( e, m, s, ld->ld_lderrno_arg );
+	} else {
+        LDAP_MUTEX_LOCK( ld, LDAP_ERR_LOCK );
+		ld->ld_errno = e;
+		if ( ld->ld_matched ) {
+			NSLDAPI_FREE( ld->ld_matched );
+		}
+		ld->ld_matched = m;
+		if ( ld->ld_error ) {
+			NSLDAPI_FREE( ld->ld_error );
+		}
+		ld->ld_error = s;
+        LDAP_MUTEX_UNLOCK( ld, LDAP_ERR_LOCK );
+	}
+
+	return( LDAP_SUCCESS );
+}
+
+
+/*
+ * Returns an LDAP error that says whether parse succeeded.  The error code
+ * from the LDAP result itself is returned in the errcodep result parameter.
+ * If any of the result params. (errcodep, matchednp, errmsgp, referralsp,
+ * or serverctrlsp) are NULL we don't return that info.
+ */
+int
+LDAP_CALL
+ldap_parse_result( LDAP *ld, LDAPMessage *res, int *errcodep, char **matchednp,
+	char **errmsgp, char ***referralsp, LDAPControl ***serverctrlsp,
+	int freeit )
+{
+	LDAPMessage		*lm;
+	int			err, errcode;
+	char			*m, *e;
+	m = e = NULL;
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_parse_result\n", 0, 0, 0 );
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) ||
+	    !NSLDAPI_VALID_LDAPMESSAGE_POINTER( res )) {
+		return( LDAP_PARAM_ERROR );
+	}
+
+	/* skip over entries and references to find next result in this chain */
+	for ( lm = res; lm != NULL; lm = lm->lm_chain ) {	
+		if ( lm->lm_msgtype != LDAP_RES_SEARCH_ENTRY &&
+		    lm->lm_msgtype != LDAP_RES_SEARCH_REFERENCE ) {
+			break;
+		}
+	}
+
+	if ( lm == NULL ) {
+		err = LDAP_NO_RESULTS_RETURNED;
+		LDAP_SET_LDERRNO( ld, err, NULL, NULL );
+		return( err );
+	}
+
+	err = nsldapi_parse_result( ld, lm->lm_msgtype, lm->lm_ber, &errcode,
+	    &m, &e, referralsp, serverctrlsp );
+
+	if ( err == LDAP_SUCCESS ) {
+		if ( errcodep != NULL ) {
+			*errcodep = errcode;
+		}
+		if ( matchednp != NULL ) {
+			*matchednp = nsldapi_strdup( m );
+		}
+		if ( errmsgp != NULL ) {
+			*errmsgp = nsldapi_strdup( e );
+		}
+
+		/*
+		 * if there are more result messages in the chain, arrange to
+		 * return the special LDAP_MORE_RESULTS_TO_RETURN "error" code.
+		 */
+		for ( lm = lm->lm_chain; lm != NULL; lm = lm->lm_chain ) {	
+			if ( lm->lm_msgtype != LDAP_RES_SEARCH_ENTRY &&
+			    lm->lm_msgtype != LDAP_RES_SEARCH_REFERENCE ) {
+				err = LDAP_MORE_RESULTS_TO_RETURN;
+				break;
+			}
+		}
+	} else { 
+	    /* In this case, m and e were already freed by ber_scanf */
+	    m = e = NULL; 
+	} 
+
+	if ( freeit ) {
+		ldap_msgfree( res );
+	}
+
+	LDAP_SET_LDERRNO( ld, ( err == LDAP_SUCCESS ) ? errcode : err, m, e );
+
+	/* nsldapi_parse_result set m and e, so we have to delete them if they exist.
+	   Only delete them if they haven't been reused for matchednp or errmsgp.
+	   if ( err == LDAP_SUCCESS ) {
+	if ( (m != NULL) && (matchednp == NULL) ) {
+	NSLDAPI_FREE( m );
+	}
+	if ( (e != NULL) && (errmsgp == NULL) ) {
+	NSLDAPI_FREE( e );
+	}
+	} */
+
+	return( err );
+}
+
+/*
+ * returns an LDAP error code indicating success or failure of parsing
+ * does NOT set any error information inside "ld"
+ */
+int
+nsldapi_parse_result( LDAP *ld, int msgtype, BerElement *rber, int *errcodep,
+    char **matchednp, char **errmsgp, char ***referralsp,
+    LDAPControl ***serverctrlsp )
+{
+	BerElement	ber;
+	ber_len_t	len;
+	ber_int_t   errcode;
+	int			berrc, err;
+	char		*m, *e;
+
+	/*
+	 * Parse the result message.  LDAPv3 result messages look like this:
+	 *
+	 *	LDAPResult ::= SEQUENCE {
+	 *		resultCode	ENUMERATED { ... },
+	 *		matchedDN	LDAPDN,
+	 *		errorMessage	LDAPString,
+	 *		referral	[3] Referral OPTIONAL
+	 *		opSpecificStuff	OPTIONAL
+	 *	}
+	 *
+	 * all wrapped up in an LDAPMessage sequence which looks like this:
+	 *	LDAPMessage ::= SEQUENCE {
+	 *		messageID	MessageID,
+	 *		LDAPResult	CHOICE { ... },	// message type
+	 *		controls	[0] Controls OPTIONAL
+	 *	}
+	 *
+	 * LDAPv2 messages don't include referrals or controls.
+	 * LDAPv1 messages don't include matchedDN, referrals, or controls.
+	 *
+	 * ldap_result() pulls out the message id, so by the time a result
+	 * message gets here we are sitting at the start of the LDAPResult.
+	 */
+
+	err = LDAP_SUCCESS;	/* optimistic */
+	m = e = NULL;
+	if ( matchednp != NULL ) {
+		*matchednp = NULL;
+	}
+	if ( errmsgp != NULL ) {
+		*errmsgp = NULL;
+	}
+	if ( referralsp != NULL ) {
+		*referralsp = NULL;
+	}
+	if ( serverctrlsp != NULL ) {
+		*serverctrlsp = NULL;
+	}
+	ber = *rber;		/* struct copy */
+
+	if ( NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION2 ) {
+		berrc = ber_scanf( &ber, "{ia}", &errcode, &e );
+	} else {
+		if (( berrc = ber_scanf( &ber, "{iaa", &errcode, &m, &e ))
+		    != LBER_ERROR ) {
+			/* check for optional referrals */
+			if ( ber_peek_tag( &ber, &len ) == LDAP_TAG_REFERRAL ) {
+				if ( referralsp == NULL ) {
+					/* skip referrals */
+					berrc = ber_scanf( &ber, "x" );
+				} else {
+					/* suck out referrals */
+					berrc = ber_scanf( &ber, "v",
+					    referralsp );
+				}
+			} else if ( referralsp != NULL ) {
+				*referralsp = NULL;
+			}
+		}
+
+		if ( berrc != LBER_ERROR ) {
+			/*
+			 * skip past optional operation-specific elements:
+			 *   bind results - serverSASLcreds
+			 *   extendedop results -  OID plus value
+			 */
+			if ( msgtype == LDAP_RES_BIND ) {
+				if ( ber_peek_tag( &ber, &len ) == 
+				    LDAP_TAG_SASL_RES_CREDS ) {
+					berrc = ber_scanf( &ber, "x" );
+				}
+			} else if ( msgtype == LDAP_RES_EXTENDED ) {
+				if ( ber_peek_tag( &ber, &len ) ==
+				    LDAP_TAG_EXOP_RES_OID ) {
+					berrc = ber_scanf( &ber, "x" );
+				}
+				if ( berrc != LBER_ERROR &&
+				    ber_peek_tag( &ber, &len ) ==
+				    LDAP_TAG_EXOP_RES_VALUE ) {
+					berrc = ber_scanf( &ber, "x" );
+				}
+			}
+		}
+
+		/* pull out controls (if requested and any are present) */
+		if ( berrc != LBER_ERROR && serverctrlsp != NULL &&
+		    ( berrc = ber_scanf( &ber, "}" )) != LBER_ERROR ) {
+			err = nsldapi_get_controls( &ber, serverctrlsp );
+		}
+	}
+
+	if ( berrc == LBER_ERROR && err == LDAP_SUCCESS ) {
+		err = LDAP_DECODING_ERROR;
+	}
+
+	if ( errcodep != NULL ) {
+		*errcodep = errcode;
+	}
+	if ( matchednp != NULL ) {
+		*matchednp = m;
+	} else if ( m != NULL ) {
+		NSLDAPI_FREE( m );
+	}
+	if ( errmsgp != NULL ) {
+		*errmsgp = e;
+	} else if ( e != NULL ) {
+		NSLDAPI_FREE( e );
+	}
+
+	return( err );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/extendop.c
@@ -0,0 +1,275 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+#include "ldap-int.h"
+
+/*
+ * ldap_extended_operation - initiate an arbitrary ldapv3 extended operation.
+ * the oid and data of the extended operation are supplied. Returns an
+ * LDAP error code.
+ *
+ * Example:
+ *	struct berval	exdata;
+ *	char		*exoid;
+ *	int		err, msgid;
+ *	... fill in oid and data ...
+ *	err = ldap_extended_operation( ld, exoid, &exdata, NULL, NULL, &msgid );
+ */
+
+int
+LDAP_CALL
+ldap_extended_operation(
+    LDAP		*ld,
+    const char		*exoid,
+    const struct berval	*exdata,
+    LDAPControl		**serverctrls,
+    LDAPControl		**clientctrls,
+    int			*msgidp
+)
+{
+	BerElement	*ber;
+	int		rc, msgid;
+
+	/*
+	 * the ldapv3 extended operation request looks like this:
+	 *
+	 *	ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
+	 *		requestName	LDAPOID,
+	 *		requestValue	OCTET STRING
+	 *	}
+	 *
+	 * all wrapped up in an LDAPMessage sequence.
+	 */
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_extended_operation\n", 0, 0, 0 );
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( LDAP_PARAM_ERROR );
+	}
+
+
+	/* only ldapv3 or higher can do extended operations */
+	if ( NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION3 ) {
+		rc = LDAP_NOT_SUPPORTED;
+		LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+		return( rc );
+	}
+
+	if ( msgidp == NULL || exoid == NULL || *exoid == '\0' ) {
+		rc = LDAP_PARAM_ERROR;
+		LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+		return( rc );
+	}
+
+	LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK );
+	msgid = ++ld->ld_msgid;
+	LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK );
+
+#if 0
+	if ( ld->ld_cache_on && ld->ld_cache_extendedop != NULL ) {
+		LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK );
+		if ( (rc = (ld->ld_cache_extendedop)( ld, msgid,
+		    LDAP_REQ_EXTENDED, exoid, cred )) != 0 ) {
+			LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+			return( rc );
+		}
+		LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+	}
+#endif
+
+	/* create a message to send */
+	if (( rc = nsldapi_alloc_ber_with_options( ld, &ber ))
+	    != LDAP_SUCCESS ) {
+		return( rc );
+	}
+
+	/* fill it in */
+	if ( exdata ) {
+		if ( ber_printf( ber, "{it{tsto}", msgid, LDAP_REQ_EXTENDED,
+						 LDAP_TAG_EXOP_REQ_OID, exoid, LDAP_TAG_EXOP_REQ_VALUE,
+						 exdata->bv_val, exdata->bv_len ) == -1 ) {
+			rc = LDAP_ENCODING_ERROR;
+			LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+			ber_free( ber, 1 );
+			return( rc );
+		}
+	} else { /* some implementations are pretty strict on empty values */
+		if ( ber_printf( ber, "{it{ts}", msgid, LDAP_REQ_EXTENDED,
+						 LDAP_TAG_EXOP_REQ_OID, exoid ) == -1 ) {
+			rc = LDAP_ENCODING_ERROR;
+			LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+			ber_free( ber, 1 );
+			return( rc );
+		}
+	}
+
+	if (( rc = nsldapi_put_controls( ld, serverctrls, 1, ber ))
+	    != LDAP_SUCCESS ) {
+		ber_free( ber, 1 );
+		return( rc );
+	}
+
+	/* send the message */
+	rc = nsldapi_send_initial_request( ld, msgid, LDAP_REQ_EXTENDED, NULL,
+		ber );
+	*msgidp = rc;
+	return( rc < 0 ? LDAP_GET_LDERRNO( ld, NULL, NULL ) : LDAP_SUCCESS );
+}
+
+
+/*
+ * ldap_extended_operation_s - perform an arbitrary ldapv3 extended operation.
+ * the oid and data of the extended operation are supplied. LDAP_SUCCESS
+ * is returned upon success, the ldap error code otherwise.
+ *
+ * Example:
+ *	struct berval	exdata, exretval;
+ *	char		*exoid;
+ *	int		rc;
+ *	... fill in oid and data ...
+ *	rc = ldap_extended_operation_s( ld, exoid, &exdata, &exretval );
+ */
+int
+LDAP_CALL
+ldap_extended_operation_s(
+    LDAP		*ld,
+    const char		*requestoid,
+    const struct berval	*requestdata,
+    LDAPControl		**serverctrls,
+    LDAPControl		**clientctrls,
+    char		**retoidp,
+    struct berval	**retdatap
+)
+{
+	int		err, msgid;
+	LDAPMessage	*result;
+
+	if (( err = ldap_extended_operation( ld, requestoid, requestdata,
+	    serverctrls, clientctrls, &msgid )) != LDAP_SUCCESS ) {
+		return( err );
+	}
+
+	if ( ldap_result( ld, msgid, 1, (struct timeval *) 0, &result )
+	    == -1 ) {
+		return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+	}
+
+	if (( err = ldap_parse_extended_result( ld, result, retoidp, retdatap,
+		0 )) != LDAP_SUCCESS ) {
+	    ldap_msgfree( result );
+	    return( err );
+	}
+
+	return( ldap_result2error( ld, result, 1 ) );
+}
+
+
+/*
+ * Pull the oid returned by the server and the data out of an extended
+ * operation result.  Return an LDAP error code.
+ */
+int
+LDAP_CALL
+ldap_parse_extended_result(
+    LDAP		*ld,
+    LDAPMessage		*res,
+    char		**retoidp,	/* may be NULL */
+    struct berval	**retdatap,	/* may be NULL */
+    int			freeit
+)
+{
+	struct berelement	ber;
+	ber_len_t			len;
+	ber_int_t			err;
+	char				*m, *e, *roid;
+	struct berval		*rdata;
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_parse_extended_result\n", 0, 0, 0 );
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( LDAP_PARAM_ERROR );
+	}
+
+        if ( !NSLDAPI_VALID_LDAPMESSAGE_EXRESULT_POINTER( res )) {
+		return( LDAP_PARAM_ERROR );
+	}
+
+	m = e = NULL;
+	ber = *(res->lm_ber);
+	if ( NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION3 ) {
+		LDAP_SET_LDERRNO( ld, LDAP_NOT_SUPPORTED, NULL, NULL );
+		return( LDAP_NOT_SUPPORTED );
+	}
+
+	if ( ber_scanf( &ber, "{iaa", &err, &m, &e ) == LBER_ERROR ) {
+		goto decoding_error;
+	}
+	roid = NULL;
+	if ( ber_peek_tag( &ber, &len ) == LDAP_TAG_EXOP_RES_OID ) {
+		if ( ber_scanf( &ber, "a", &roid ) == LBER_ERROR ) {
+			goto decoding_error;
+		}
+	}
+	if ( retoidp != NULL ) {
+		*retoidp = roid;
+	} else if ( roid != NULL ) {
+		NSLDAPI_FREE( roid );
+	}
+
+	rdata = NULL;
+	if ( ber_peek_tag( &ber, &len ) == LDAP_TAG_EXOP_RES_VALUE ) {
+		if ( ber_scanf( &ber, "O", &rdata ) == LBER_ERROR ) {
+			goto decoding_error;
+		}
+	}
+	if ( retdatap != NULL ) {
+		*retdatap = rdata;
+	} else if ( rdata != NULL ) {
+		ber_bvfree( rdata );
+	}
+
+	LDAP_SET_LDERRNO( ld, err, m, e );
+
+	if ( freeit ) {
+		ldap_msgfree( res );
+	}
+
+	return( LDAP_SUCCESS );
+
+decoding_error:;
+	LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
+	return( LDAP_DECODING_ERROR );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/free.c
@@ -0,0 +1,156 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ *  Copyright (c) 1994 The Regents of the University of Michigan.
+ *  All rights reserved.
+ */
+/*
+ *  free.c - some free routines are included here to avoid having to
+ *           link in lots of extra code when not using certain features
+ */
+
+#if 0
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1994 The Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+void
+LDAP_CALL
+ldap_getfilter_free( LDAPFiltDesc *lfdp )
+{
+    LDAPFiltList	*flp, *nextflp;
+    LDAPFiltInfo	*fip, *nextfip;
+
+    if ( lfdp == NULL ) {
+	return;
+    }
+
+    for ( flp = lfdp->lfd_filtlist; flp != NULL; flp = nextflp ) {
+	for ( fip = flp->lfl_ilist; fip != NULL; fip = nextfip ) {
+	    nextfip = fip->lfi_next;
+	    NSLDAPI_FREE( fip->lfi_filter );
+	    NSLDAPI_FREE( fip->lfi_desc );
+	    NSLDAPI_FREE( fip );
+	}
+	nextflp = flp->lfl_next;
+	NSLDAPI_FREE( flp->lfl_pattern );
+	NSLDAPI_FREE( flp->lfl_delims );
+	NSLDAPI_FREE( flp->lfl_tag );
+	NSLDAPI_FREE( flp );
+    }
+
+    if ( lfdp->lfd_curval != NULL ) {
+	NSLDAPI_FREE( lfdp->lfd_curval );
+    }
+    if ( lfdp->lfd_curvalcopy != NULL ) {
+	NSLDAPI_FREE( lfdp->lfd_curvalcopy );
+    }
+    if ( lfdp->lfd_curvalwords != NULL ) {
+	NSLDAPI_FREE( lfdp->lfd_curvalwords );
+    }
+    if ( lfdp->lfd_filtprefix != NULL ) {
+	NSLDAPI_FREE( lfdp->lfd_filtprefix );
+    }
+    if ( lfdp->lfd_filtsuffix != NULL ) {
+	NSLDAPI_FREE( lfdp->lfd_filtsuffix );
+    }
+
+    NSLDAPI_FREE( lfdp );
+}
+
+
+/*
+ * free a null-terminated array of pointers to mod structures. the
+ * structures are freed, not the array itself, unless the freemods
+ * flag is set.
+ */
+void
+LDAP_CALL
+ldap_mods_free( LDAPMod **mods, int freemods )
+{
+	int	i;
+
+	if ( !NSLDAPI_VALID_LDAPMOD_ARRAY( mods )) {
+		return;
+	}
+
+	for ( i = 0; mods[i] != NULL; i++ ) {
+		if ( mods[i]->mod_op & LDAP_MOD_BVALUES ) {
+			if ( mods[i]->mod_bvalues != NULL ) {
+				ber_bvecfree( mods[i]->mod_bvalues );
+			}
+		} else if ( mods[i]->mod_values != NULL ) {
+			ldap_value_free( mods[i]->mod_values );
+		}
+		if ( mods[i]->mod_type != NULL ) {
+			NSLDAPI_FREE( mods[i]->mod_type );
+		}
+		NSLDAPI_FREE( (char *) mods[i] );
+	}
+
+	if ( freemods )
+		NSLDAPI_FREE( (char *) mods );
+}
+
+
+/*
+ * ldap_memfree() is needed to ensure that memory allocated by the C runtime
+ * assocated with libldap is freed by the same runtime code.
+ */
+void
+LDAP_CALL
+ldap_memfree( void *s )
+{
+	if ( s != NULL ) {
+		NSLDAPI_FREE( s );
+	}
+}
+
+
+/*
+ * ldap_ber_free() is just a cover for ber_free()
+ * ber_free() checks for ber == NULL, so we don't bother.
+ */
+void
+LDAP_CALL
+ldap_ber_free( BerElement *ber, int freebuf )
+{
+	ber_free( ber, freebuf );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/freevalues.c
@@ -0,0 +1,73 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ *  Copyright (c) 1990 Regents of the University of Michigan.
+ *  All rights reserved.
+ */
+/*
+ *  freevalues.c
+ */
+
+#include "ldap-int.h"
+
+void
+LDAP_CALL
+ldap_value_free( char **vals )
+{
+	int	i;
+
+	if ( vals == NULL )
+		return;
+	for ( i = 0; vals[i] != NULL; i++ )
+		NSLDAPI_FREE( vals[i] );
+	NSLDAPI_FREE( (char *) vals );
+}
+
+void
+LDAP_CALL
+ldap_value_free_len( struct berval **vals )
+{
+	int	i;
+
+	if ( vals == NULL )
+		return;
+	for ( i = 0; vals[i] != NULL; i++ ) {
+		NSLDAPI_FREE( vals[i]->bv_val );
+		NSLDAPI_FREE( vals[i] );
+	}
+	NSLDAPI_FREE( (char *) vals );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/friendly.c
@@ -0,0 +1,151 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ *  Copyright (c) 1990 Regents of the University of Michigan.
+ *  All rights reserved.
+ */
+/*
+ *  friendly.c
+ */
+
+#if 0
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1993 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+char *
+LDAP_CALL
+ldap_friendly_name( char *filename, char *name, FriendlyMap *map )
+{
+	int	i, entries;
+	FILE	*fp;
+	char	*s;
+	char	buf[BUFSIZ];
+
+	if ( map == NULL ) {
+		return( name );
+	}
+    if ( NULL == name)
+    {
+        return (name);
+    }
+
+	if ( *map == NULL ) {
+		if ( (fp = NSLDAPI_FOPEN( filename, "r" )) == NULL )
+			return( name );
+
+		entries = 0;
+		while ( fgets( buf, sizeof(buf), fp ) != NULL ) {
+			if ( buf[0] != '#' )
+				entries++;
+		}
+		rewind( fp );
+
+		if ( (*map = (FriendlyMap)NSLDAPI_MALLOC( (entries + 1) *
+		    sizeof(struct friendly) )) == NULL ) {
+			fclose( fp );
+			return( name );
+		}
+
+		i = 0;
+		while ( fgets( buf, sizeof(buf), fp ) != NULL && i < entries ) {
+			if ( buf[0] == '#' )
+				continue;
+
+			if ( (s = strchr( buf, '\n' )) != NULL )
+				*s = '\0';
+
+			if ( (s = strchr( buf, '\t' )) == NULL )
+				continue;
+			*s++ = '\0';
+
+			if ( *s == '"' ) {
+				int	esc = 0, found = 0;
+
+				for ( ++s; *s && !found; s++ ) {
+					switch ( *s ) {
+					case '\\':
+						esc = 1;
+						break;
+					case '"':
+						if ( !esc )
+							found = 1;
+						/* FALL */
+					default:
+						esc = 0;
+						break;
+					}
+				}
+			}
+
+			(*map)[i].f_unfriendly = nsldapi_strdup( buf );
+			(*map)[i].f_friendly = nsldapi_strdup( s );
+			i++;
+		}
+
+		fclose( fp );
+		(*map)[i].f_unfriendly = NULL;
+	}
+
+	for ( i = 0; (*map)[i].f_unfriendly != NULL; i++ ) {
+		if ( strcasecmp( name, (*map)[i].f_unfriendly ) == 0 )
+			return( (*map)[i].f_friendly );
+	}
+	return( name );
+}
+
+
+void
+LDAP_CALL
+ldap_free_friendlymap( FriendlyMap *map )
+{
+	struct friendly* pF;
+
+	if ( map == NULL || *map == NULL ) {
+		return;
+	}
+
+	for ( pF = *map; pF->f_unfriendly; pF++ ) {
+		NSLDAPI_FREE( pF->f_unfriendly );
+		NSLDAPI_FREE( pF->f_friendly );
+	}
+	NSLDAPI_FREE( *map );
+	*map = NULL;
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/getattr.c
@@ -0,0 +1,150 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ *  Copyright (c) 1990 Regents of the University of Michigan.
+ *  All rights reserved.
+ */
+/*
+ *  getattr.c
+ */
+
+#if 0
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+
+static unsigned long
+bytes_remaining( BerElement *ber )
+{
+	ber_len_t	len;
+
+	if ( ber_get_option( ber, LBER_OPT_REMAINING_BYTES, &len ) != 0 ) {
+		return( 0 );	/* not sure what else to do.... */
+	}
+	return( len );
+}
+
+
+char *
+LDAP_CALL
+ldap_first_attribute( LDAP *ld, LDAPMessage *entry, BerElement **ber )
+{
+	char		*attr;
+	int			err;
+	ber_len_t	seqlength;
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_first_attribute\n", 0, 0, 0 );
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( NULL );		/* punt */
+	}
+
+	if ( ber == NULL || !NSLDAPI_VALID_LDAPMESSAGE_ENTRY_POINTER( entry )) {
+		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+		return( NULL );
+	}
+	
+	if ( nsldapi_alloc_ber_with_options( ld, ber ) != LDAP_SUCCESS ) {
+		return( NULL );
+	}
+
+	**ber = *entry->lm_ber;
+
+	attr = NULL;			/* pessimistic */
+	err = LDAP_DECODING_ERROR;	/* ditto */
+
+	/* 
+	 * Skip past the sequence, dn, and sequence of sequence.
+	 * Reset number of bytes remaining so we confine the rest of our
+	 * decoding to the current sequence.
+	 */
+	if ( ber_scanf( *ber, "{xl{", &seqlength ) != LBER_ERROR &&
+	     ber_set_option( *ber, LBER_OPT_REMAINING_BYTES, &seqlength )
+	    == 0 ) {
+		/* snarf the attribute type, and skip the set of values,
+		 * leaving us positioned right before the next attribute
+		 * type/value sequence.
+		 */
+		if ( ber_scanf( *ber, "{ax}", &attr ) != LBER_ERROR ||
+		    bytes_remaining( *ber ) == 0 ) {
+			err = LDAP_SUCCESS;
+		}
+	}
+
+	LDAP_SET_LDERRNO( ld, err, NULL, NULL );
+	if ( attr == NULL || err != LDAP_SUCCESS ) {
+		ber_free( *ber, 0 );
+		*ber = NULL;
+	}
+	return( attr );
+}
+
+/* ARGSUSED */
+char *
+LDAP_CALL
+ldap_next_attribute( LDAP *ld, LDAPMessage *entry, BerElement *ber )
+{
+	char	*attr;
+	int	err;
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_next_attribute\n", 0, 0, 0 );
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( NULL );		/* punt */
+	}
+
+	if ( ber == NULL || !NSLDAPI_VALID_LDAPMESSAGE_ENTRY_POINTER( entry )) {
+		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+		return( NULL );
+	}
+
+	attr = NULL;			/* pessimistic */
+	err = LDAP_DECODING_ERROR;	/* ditto */
+
+	/* skip sequence, snarf attribute type, skip values */
+	if ( ber_scanf( ber, "{ax}", &attr ) != LBER_ERROR ||
+	    bytes_remaining( ber ) == 0 ) {
+		err = LDAP_SUCCESS;
+	}
+
+	LDAP_SET_LDERRNO( ld, err, NULL, NULL );
+	return( attr );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/getdn.c
@@ -0,0 +1,371 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ *  Copyright (c) 1994 Regents of the University of Michigan.
+ *  All rights reserved.
+ */
+/*
+ *  getdn.c
+ */
+
+#if 0
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+char *
+LDAP_CALL
+ldap_get_dn( LDAP *ld, LDAPMessage *entry )
+{
+	char			*dn;
+	struct berelement	tmp;
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_get_dn\n", 0, 0, 0 );
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( NULL );		/* punt */
+	}
+
+	if ( !NSLDAPI_VALID_LDAPMESSAGE_ENTRY_POINTER( entry )) {
+		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+		return( NULL );
+	}
+
+	tmp = *entry->lm_ber;	/* struct copy */
+	if ( ber_scanf( &tmp, "{a", &dn ) == LBER_ERROR ) {
+		LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
+		return( NULL );
+	}
+
+	return( dn );
+}
+
+char *
+LDAP_CALL
+ldap_dn2ufn( const char *dn )
+{
+	char	*p, *ufn, *r;
+	size_t	plen;
+	int	state;
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_dn2ufn\n", 0, 0, 0 );
+
+	if ( dn == NULL ) {
+		dn = "";
+	}
+
+	if ( ldap_is_dns_dn( dn ) || ( p = strchr( dn, '=' )) == NULL )
+		return( nsldapi_strdup( (char *)dn ));
+
+	ufn = nsldapi_strdup( ++p );
+
+#define INQUOTE		1
+#define OUTQUOTE	2
+	state = OUTQUOTE;
+	for ( p = ufn, r = ufn; *p; p += plen ) {
+	    plen = 1;
+		switch ( *p ) {
+		case '\\':
+			if ( *++p == '\0' )
+				plen=0;
+			else {
+				*r++ = '\\';
+				r += (plen = LDAP_UTF8COPY(r,p));
+			}
+			break;
+		case '"':
+			if ( state == INQUOTE )
+				state = OUTQUOTE;
+			else
+				state = INQUOTE;
+			*r++ = *p;
+			break;
+		case ';':
+		case ',':
+			if ( state == OUTQUOTE )
+				*r++ = ',';
+			else
+				*r++ = *p;
+			break;
+		case '=':
+			if ( state == INQUOTE )
+				*r++ = *p;
+			else {
+				char	*rsave = r;
+				LDAP_UTF8DEC(r);
+				*rsave = '\0';
+				while ( !ldap_utf8isspace( r ) && *r != ';'
+				    && *r != ',' && r > ufn )
+					LDAP_UTF8DEC(r);
+				LDAP_UTF8INC(r);
+
+				if ( strcasecmp( r, "c" )
+				    && strcasecmp( r, "o" )
+				    && strcasecmp( r, "ou" )
+				    && strcasecmp( r, "st" )
+				    && strcasecmp( r, "l" )
+				    && strcasecmp( r, "dc" )
+				    && strcasecmp( r, "uid" )
+				    && strcasecmp( r, "cn" ) ) {
+					r = rsave;
+					*r++ = '=';
+				}
+			}
+			break;
+		default:
+			r += (plen = LDAP_UTF8COPY(r,p));
+			break;
+		}
+	}
+	*r = '\0';
+
+	return( ufn );
+}
+
+char **
+LDAP_CALL
+ldap_explode_dns( const char *dn )
+{
+	int	ncomps, maxcomps;
+	char	*s, *cpydn;
+	char	**rdns;
+#ifdef HAVE_STRTOK_R	/* defined in portable.h */
+	char	*lasts;
+#endif
+
+	if ( dn == NULL ) {
+		dn = "";
+	}
+
+	if ( (rdns = (char **)NSLDAPI_MALLOC( 8 * sizeof(char *) )) == NULL ) {
+		return( NULL );
+	}
+
+	maxcomps = 8;
+	ncomps = 0;
+	cpydn = nsldapi_strdup( (char *)dn );
+	for ( s = STRTOK( cpydn, "@.", &lasts ); s != NULL;
+	    s = STRTOK( NULL, "@.", &lasts ) ) {
+		if ( ncomps == maxcomps ) {
+			maxcomps *= 2;
+			if ( (rdns = (char **)NSLDAPI_REALLOC( rdns, maxcomps *
+			    sizeof(char *) )) == NULL ) {
+				NSLDAPI_FREE( cpydn );
+				return( NULL );
+			}
+		}
+		rdns[ncomps++] = nsldapi_strdup( s );
+	}
+	rdns[ncomps] = NULL;
+	NSLDAPI_FREE( cpydn );
+
+	return( rdns );
+}
+
+#define LDAP_DN		1
+#define LDAP_RDN	2
+
+static char **
+ldap_explode( const char *dn, const int notypes, const int nametype )
+{
+	char	*p, *q, *rdnstart, **rdns = NULL;
+	size_t	plen = 0;
+	int		state = 0;
+	int		count = 0;
+	int		startquote = 0;
+	int		endquote = 0;
+	int		len = 0;
+	int		goteq = 0;
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_explode\n", 0, 0, 0 );
+
+	if ( dn == NULL ) {
+		dn = "";
+	}
+
+#if 0
+	if ( ldap_is_dns_dn( dn ) ) {
+		return( ldap_explode_dns( dn ) );
+	}
+#endif
+
+	while ( ldap_utf8isspace( (char *)dn )) { /* ignore leading spaces */
+		++dn;
+	}
+
+	p = rdnstart = (char *) dn;
+	state = OUTQUOTE;
+
+	do {
+		p += plen;
+		plen = 1;
+		switch ( *p ) {
+		case '\\':
+			if ( *++p == '\0' )
+				p--;
+			else
+				plen = LDAP_UTF8LEN(p);
+			break;
+		case '"':
+			if ( state == INQUOTE )
+				state = OUTQUOTE;
+			else
+				state = INQUOTE;
+			break;
+		case '+': if ( nametype != LDAP_RDN ) break;
+		case ';':
+		case ',':
+		case '\0':
+			if ( state == OUTQUOTE ) {
+				/*
+				 * semicolon and comma are not valid RDN
+				 * separators.
+				 */
+				if ( nametype == LDAP_RDN && 
+					( *p == ';' || *p == ',' || !goteq)) {
+					ldap_charray_free( rdns );
+					return NULL;
+				}
+				if ( (*p == ',' || *p == ';') && !goteq ) {
+                                   /* If we get here, we have a case similar
+				    * to <attr>=<value>,<string>,<attr>=<value>
+				    * This is not a valid dn */
+				    ldap_charray_free( rdns );
+				    return NULL;
+				}
+				goteq = 0;
+				++count;
+				if ( rdns == NULL ) {
+					if (( rdns = (char **)NSLDAPI_MALLOC( 8
+						 * sizeof( char *))) == NULL )
+						return( NULL );
+				} else if ( count >= 8 ) {
+					if (( rdns = (char **)NSLDAPI_REALLOC(
+					    rdns, (count+1) *
+					    sizeof( char *))) == NULL )
+						return( NULL );
+				}
+				rdns[ count ] = NULL;
+				endquote = 0;
+				if ( notypes ) {
+					for ( q = rdnstart;
+					    q < p && *q != '='; ++q ) {
+						;
+					}
+					if ( q < p ) { /* *q == '=' */
+						rdnstart = ++q;
+					}
+					if ( *rdnstart == '"' ) {
+						startquote = 1;
+						++rdnstart;
+					}
+					
+					if ( (*(p-1) == '"') && startquote ) {
+						endquote = 1;
+						--p;
+					}
+				}
+
+				len = p - rdnstart;
+				if (( rdns[ count-1 ] = (char *)NSLDAPI_CALLOC(
+				    1, len + 1 )) != NULL ) {
+				    	SAFEMEMCPY( rdns[ count-1 ], rdnstart,
+					    len );
+					if ( !endquote ) {
+                                                /* trim trailing spaces unless
+                                                 * they are properly escaped */
+						while ( len > 0 &&
+						    ldap_utf8isspace(
+                                                    &rdns[count-1][len-1] ) &&
+                                                    ((len == 1) || (rdns[count-1][len-2] != '\\'))) {
+                                                         --len;
+						}
+					}
+					rdns[ count-1 ][ len ] = '\0';
+				}
+
+				/*
+				 *  Don't forget to increment 'p' back to where
+				 *  it should be.  If we don't, then we will
+				 *  never get past an "end quote."
+				 */
+				if ( endquote == 1 )
+					p++;
+
+				rdnstart = *p ? p + 1 : p;
+				while ( ldap_utf8isspace( rdnstart ))
+					++rdnstart;
+			}
+			break;
+		case '=':
+			if ( state == OUTQUOTE ) {
+				goteq = 1;
+			}
+			/* FALL */
+		default:
+			plen = LDAP_UTF8LEN(p);
+			break;
+		}
+	} while ( *p );
+
+	return( rdns );
+}
+
+char **
+LDAP_CALL
+ldap_explode_dn( const char *dn, const int notypes )
+{
+	return( ldap_explode( dn, notypes, LDAP_DN ) );
+}
+
+char **
+LDAP_CALL
+ldap_explode_rdn( const char *rdn, const int notypes )
+{
+	return( ldap_explode( rdn, notypes, LDAP_RDN ) );
+}
+
+int
+LDAP_CALL
+ldap_is_dns_dn( const char *dn )
+{
+	return( dn != NULL && dn[ 0 ] != '\0' && strchr( dn, '=' ) == NULL &&
+	    strchr( dn, ',' ) == NULL );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/getdxbyname.c
@@ -0,0 +1,279 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ *  Copyright (c) 1995 Regents of the University of Michigan.
+ *  All rights reserved.
+ */
+/*
+ * nsldapi_getdxbyname - retrieve DX records from the DNS (from 
+ * TXT records for now)
+ */
+
+#include <stdio.h>
+
+#ifdef LDAP_DNS
+
+XXX not MT-safe XXX
+
+#include <string.h>
+#include <ctype.h>
+
+#ifdef macintosh
+#include <stdlib.h>
+#include "macos.h"
+#endif /* macintosh */
+
+#ifdef _WINDOWS
+#include <windows.h>
+#endif
+
+#if !defined(macintosh) && !defined(DOS) && !defined( _WINDOWS )
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <resolv.h>
+#endif
+#include "ldap-int.h"
+
+#if defined( DOS ) 
+#include "msdos.h"
+#endif /* DOS */
+
+
+#ifdef NEEDPROTOS
+static char ** decode_answer( unsigned char *answer, int len );
+#else /* NEEDPROTOS */
+static char **decode_answer();
+#endif /* NEEDPROTOS */
+
+extern int h_errno;
+extern char *h_errlist[];
+
+
+#define MAX_TO_SORT	32
+
+
+/*
+ * nsldapi_getdxbyname - lookup DNS DX records for domain and return an ordered
+ *	array.
+ */
+char **
+nsldapi_getdxbyname( char *domain )
+{
+    unsigned char	buf[ PACKETSZ ];
+    char		**dxs;
+    int			rc;
+
+    LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_getdxbyname( %s )\n", domain, 0, 0 );
+
+    memset( buf, 0, sizeof( buf ));
+
+    /* XXX not MT safe XXX */
+    if (( rc = res_search( domain, C_IN, T_TXT, buf, sizeof( buf ))) < 0
+		|| ( rc > sizeof( buf ))
+		|| ( dxs = decode_answer( buf, rc )) == NULL ) {
+	/*
+	 * punt:  return list consisting of the original domain name only
+	 */
+	if (( dxs = (char **)NSLDAPI_MALLOC( 2 * sizeof( char * ))) == NULL ||
+		( dxs[ 0 ] = nsldapi_strdup( domain )) == NULL ) {
+	    if ( dxs != NULL ) {
+		NSLDAPI_FREE( dxs );
+	    }
+	    dxs = NULL;
+	} else {
+	    dxs[ 1 ] = NULL;
+	}
+    }
+
+    return( dxs );
+}
+
+
+static char **
+decode_answer( unsigned char *answer, int len )
+{
+    HEADER		*hp;
+    char		buf[ 256 ], **dxs;
+    unsigned char	*eom, *p;
+    int			ancount, err, rc, type, class, dx_count, rr_len;
+    int			dx_pref[ MAX_TO_SORT ];
+
+#ifdef LDAP_DEBUG
+    if ( ldap_debug & LDAP_DEBUG_PACKETS ) {
+/*	__p_query( answer );	*/
+    }
+#endif /* LDAP_DEBUG */
+
+    dxs = NULL;
+    hp = (HEADER *)answer;
+    eom = answer + len;
+
+    if ( len < sizeof( *hp ) ) {
+	h_errno = NO_RECOVERY;
+	return( NULL );
+    }
+
+    if ( ntohs( hp->qdcount ) != 1 ) {
+	h_errno = NO_RECOVERY;
+	return( NULL );
+    }
+
+    ancount = ntohs( hp->ancount );
+    if ( ancount < 1 ) {
+	h_errno = NO_DATA;
+	return( NULL );
+    }
+
+    /*
+     * skip over the query
+     */
+    p = answer + HFIXEDSZ;
+    if (( rc = dn_expand( answer, eom, p, buf, sizeof( buf ))) < 0 ) {
+	h_errno = NO_RECOVERY;
+	return( NULL );
+    }
+    p += ( rc + QFIXEDSZ );
+
+    /*
+     * pull out the answers we are interested in
+     */
+    err = dx_count = 0;
+    while ( ancount > 0 && err == 0 && p < eom ) {
+	if (( rc = dn_expand( answer, eom, p, buf, sizeof( buf ))) < 0 ) {
+	    err = NO_RECOVERY;
+	    continue;
+	}
+	p += rc;	/* skip over name */
+	if ( p + 3 * INT16SZ + INT32SZ > eom ) {
+	    err = NO_RECOVERY;
+	    continue;
+	}
+	type = _getshort( p );
+	p += INT16SZ;
+	class = _getshort( p );
+	p += INT16SZ;
+	p += INT32SZ;		/* skip over TTL */
+	rr_len = _getshort( p );
+	p += INT16SZ;
+	if ( p + rr_len > eom ) {
+	    err = NO_RECOVERY;
+	    continue;
+	}
+	if ( class == C_IN && type == T_TXT ) {
+	    int 	i, n, pref, txt_len;
+	    char	*q, *r;
+
+	    q = (char *)p;
+	    while ( q < (char *)p + rr_len && err == 0 ) {
+		if ( *q >= 3 && strncasecmp( q + 1, "dx:", 3 ) == 0 ) {
+		    txt_len = *q - 3;
+		    r = q + 4;
+		    while ( isspace( *r )) { 
+			++r;
+			--txt_len;
+		    }
+		    pref = 0;
+		    while ( isdigit( *r )) {
+			pref *= 10;
+			pref += ( *r - '0' );
+			++r;
+			--txt_len;
+		    }
+		    if ( dx_count < MAX_TO_SORT - 1 ) {
+			dx_pref[ dx_count ] = pref;
+		    }
+		    while ( isspace( *r )) { 
+			++r;
+			--txt_len;
+		    }
+		    if ( dx_count == 0 ) {
+			dxs = (char **)NSLDAPI_MALLOC( 2 * sizeof( char * ));
+		    } else {
+			dxs = (char **)NSLDAPI_REALLOC( dxs,
+				( dx_count + 2 ) * sizeof( char * ));
+		    }
+		    if ( dxs == NULL || ( dxs[ dx_count ] =
+			    (char *)NSLDAPI_CALLOC( 1, txt_len + 1 ))
+			    == NULL ) {
+			err = NO_RECOVERY;
+			continue;
+		    }
+		    SAFEMEMCPY( dxs[ dx_count ], r, txt_len );
+		    dxs[ ++dx_count ] = NULL;
+		}
+		q += ( *q + 1 );	/* move past last TXT record */
+	    }
+	}
+	p += rr_len;
+    }
+
+    if ( err == 0 ) {
+	if ( dx_count == 0 ) {
+	    err = NO_DATA;
+	} else {
+	    /*
+	     * sort records based on associated preference value
+	     */
+	    int		i, j, sort_count, tmp_pref;
+	    char	*tmp_dx;
+
+	    sort_count = ( dx_count < MAX_TO_SORT ) ? dx_count : MAX_TO_SORT;
+	    for ( i = 0; i < sort_count; ++i ) {
+		for ( j = i + 1; j < sort_count; ++j ) {
+		    if ( dx_pref[ i ] > dx_pref[ j ] ) {
+			tmp_pref = dx_pref[ i ];
+			dx_pref[ i ] = dx_pref[ j ];
+			dx_pref[ j ] = tmp_pref;
+			tmp_dx = dxs[ i ];
+			dxs[ i ] = dxs[ j ];
+			dxs[ j ] = tmp_dx;
+		    }
+		}
+	    }
+	}
+    }
+
+    h_errno = err;
+    return( dxs );
+}
+
+#endif /* LDAP_DNS */
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/geteffectiverightsctrl.c
@@ -0,0 +1,109 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Sun LDAP C SDK.
+ *
+ * The Initial Developer of the Original Code is Sun Microsystems, Inc.
+ *
+ * Portions created by Sun Microsystems, Inc are Copyright (C) 2005
+ * Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ldap-int.h"
+
+/* ldap_create_geteffectiveRights_control
+
+   Create Effective Rights control.
+
+   Parameters are  
+
+   ld              LDAP pointer to the desired connection 
+
+   authzid		   RFC2829 section 9, eg "dn:<DN>".
+                   NULL or empty string means get bound user's rights, 
+                   just "dn:" means get anonymous user's rights.
+                   
+   attrlist        additional attributes for which rights info is 
+                   requrested. NULL means "just the ones returned 
+                   with the search operation".
+
+   ctl_iscritical  Indicates whether the control is critical of not. If
+                   this field is non-zero, the operation will only be car-
+                   ried out if the control is recognized by the server
+                   and/or client
+
+   ctrlp           the address of a place to put the constructed control 
+*/
+
+int
+LDAP_CALL
+ldap_create_geteffectiveRights_control (
+     LDAP *ld, 
+     const char *authzid,
+	 const char **attrlist, 
+     const char ctl_iscritical,
+     LDAPControl **ctrlp   
+)
+{
+	BerElement		*ber;
+	int				rc;
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( LDAP_PARAM_ERROR );
+	}
+
+	if (  ctrlp == NULL ) {
+		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+		return ( LDAP_PARAM_ERROR );
+	}
+	if (NULL == authzid)
+	{
+	    authzid = "";
+	}
+
+	/* create a ber package to hold the controlValue */
+	if ( ( nsldapi_alloc_ber_with_options( ld, &ber ) ) != LDAP_SUCCESS ) {
+		LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+		return( LDAP_NO_MEMORY );
+	}
+
+	if ( LBER_ERROR == ber_printf( ber, "{s{v}}", authzid, attrlist ) ) {
+        LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
+        ber_free( ber, 1 );
+        return( LDAP_ENCODING_ERROR );
+    }
+
+	rc = nsldapi_build_control( LDAP_CONTROL_GETEFFECTIVERIGHTS_REQUEST, ber, 1,
+	    ctl_iscritical, ctrlp );
+
+	LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+	return( rc );
+
+}
+
+
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/getentry.c
@@ -0,0 +1,141 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ *  Copyright (c) 1990 Regents of the University of Michigan.
+ *  All rights reserved.
+ */
+/*
+ *  getentry.c
+ */
+
+#if 0
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+LDAPMessage *
+LDAP_CALL
+ldap_first_entry( LDAP *ld, LDAPMessage *chain )
+{
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) || chain == NULLMSG ) {
+		return( NULLMSG );
+	}
+
+	if ( chain->lm_msgtype == LDAP_RES_SEARCH_ENTRY ) {
+		return( chain );
+	}
+
+	return( ldap_next_entry( ld, chain ));
+}
+
+
+LDAPMessage *
+LDAP_CALL
+ldap_next_entry( LDAP *ld, LDAPMessage *entry )
+{
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) || entry == NULLMSG ) {
+		return( NULLMSG );
+	}
+
+	for ( entry = entry->lm_chain; entry != NULLMSG;
+	    entry = entry->lm_chain ) {
+		if ( entry->lm_msgtype == LDAP_RES_SEARCH_ENTRY ) {
+			return( entry );
+		}
+	}
+
+	return( NULLMSG );
+}
+
+int
+LDAP_CALL
+ldap_count_entries( LDAP *ld, LDAPMessage *chain )
+{
+	int	i;
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( -1 );
+	}
+
+	for ( i = 0; chain != NULL; chain = chain->lm_chain ) {
+		if ( chain->lm_msgtype == LDAP_RES_SEARCH_ENTRY ) {
+			++i;
+		}
+	}
+
+	return( i );
+}
+
+
+int
+LDAP_CALL
+ldap_get_entry_controls( LDAP *ld, LDAPMessage *entry,
+	LDAPControl ***serverctrlsp )
+{
+	int		rc;
+	BerElement	tmpber;
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_get_entry_controls\n", 0, 0, 0 );
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( LDAP_PARAM_ERROR );
+	}
+
+	if ( !NSLDAPI_VALID_LDAPMESSAGE_ENTRY_POINTER( entry )
+	    || serverctrlsp == NULL ) {
+		rc = LDAP_PARAM_ERROR;
+		goto report_error_and_return;
+	}
+
+	*serverctrlsp = NULL;
+	tmpber = *entry->lm_ber;	/* struct copy */
+
+	/* skip past dn and entire attribute/value list */ 
+	if ( ber_scanf( &tmpber, "{xx" ) == LBER_ERROR ) {
+		rc = LDAP_DECODING_ERROR;
+		goto report_error_and_return;
+	}
+
+	rc = nsldapi_get_controls( &tmpber, serverctrlsp );
+
+report_error_and_return:
+	LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+	return( rc );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/getfilter.c
@@ -0,0 +1,557 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ *  Copyright (c) 1993 Regents of the University of Michigan.
+ *  All rights reserved.
+ */
+/*
+ *  getfilter.c -- optional add-on to libldap
+ */
+
+#if 0
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1993 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+#include "regex.h"
+
+static int break_into_words( char *str, char *delims, char ***wordsp );
+
+#if !defined( macintosh ) && !defined( DOS )
+extern char	* LDAP_CALL re_comp();
+#endif
+
+#define FILT_MAX_LINE_LEN	1024
+
+LDAPFiltDesc *
+LDAP_CALL
+ldap_init_getfilter( char *fname )
+{
+    FILE		*fp;
+    char		*buf;
+    long		rlen, len;
+    int 		eof;
+    LDAPFiltDesc	*lfdp;
+
+    if (( fp = NSLDAPI_FOPEN( fname, "r" )) == NULL ) {
+	return( NULL );
+    }
+
+    if ( fseek( fp, 0L, SEEK_END ) != 0 ) {	/* move to end to get len */
+	fclose( fp );
+	return( NULL );
+    }
+
+    len = ftell( fp );
+
+    if ( fseek( fp, 0L, SEEK_SET ) != 0 ) {	/* back to start of file */
+	fclose( fp );
+	return( NULL );
+    }
+
+    if (( buf = NSLDAPI_MALLOC( (size_t)len )) == NULL ) {
+	fclose( fp );
+	return( NULL );
+    }
+
+    rlen = fread( buf, 1, (size_t)len, fp );
+    eof = feof( fp );
+    fclose( fp );
+
+    if ( rlen != len && !eof ) {	/* error:  didn't get the whole file */
+	NSLDAPI_FREE( buf );
+	return( NULL );
+    }
+
+
+    lfdp = ldap_init_getfilter_buf( buf, rlen );
+    NSLDAPI_FREE( buf );
+
+    return( lfdp );
+}
+
+
+LDAPFiltDesc *
+LDAP_CALL
+ldap_init_getfilter_buf( char *buf, long buflen )
+{
+    LDAPFiltDesc	*lfdp;
+    LDAPFiltList	*flp, *nextflp;
+    LDAPFiltInfo	*fip, *nextfip;
+    char		*errmsg, *tag, **tok;
+    int			tokcnt, i;
+
+    if ( (buf == NULL) || (buflen < 0) ||
+	 ( lfdp = (LDAPFiltDesc *)NSLDAPI_CALLOC(1, sizeof( LDAPFiltDesc)))
+	 == NULL ) {
+	return( NULL );
+    }
+
+    flp = nextflp = NULL;
+    fip = NULL;
+    tag = NULL;
+
+    while ( buflen > 0 && ( tokcnt = nsldapi_next_line_tokens( &buf, &buflen,
+	    &tok )) > 0 ) {
+	switch( tokcnt ) {
+	case 1:		/* tag line */
+	    if ( tag != NULL ) {
+		NSLDAPI_FREE( tag );
+	    }
+	    tag = tok[ 0 ];
+	    NSLDAPI_FREE( tok );
+	    break;
+	case 4:
+	case 5:		/* start of filter info. list */
+	    if (( nextflp = (LDAPFiltList *)NSLDAPI_CALLOC( 1,
+		    sizeof( LDAPFiltList ))) == NULL ) {
+		ldap_getfilter_free( lfdp );
+		return( NULL );
+	    }
+	    nextflp->lfl_tag = nsldapi_strdup( tag );
+	    nextflp->lfl_pattern = tok[ 0 ];
+	    if (( errmsg = re_comp( nextflp->lfl_pattern )) != NULL ) {
+		char    msg[512];
+		ldap_getfilter_free( lfdp );
+#ifdef HAVE_SNPRINTF
+		snprintf( msg, sizeof(msg),
+#else
+		sprintf( msg,
+#endif
+			"bad regular expression \"%s\" - %s\n",
+			nextflp->lfl_pattern, errmsg );
+		ber_err_print( msg );
+		nsldapi_free_strarray( tok );
+		return( NULL );
+	    }
+		
+	    nextflp->lfl_delims = tok[ 1 ];
+	    nextflp->lfl_ilist = NULL;
+	    nextflp->lfl_next = NULL;
+	    if ( flp == NULL ) {	/* first one */
+		lfdp->lfd_filtlist = nextflp;
+	    } else {
+		flp->lfl_next = nextflp;
+	    }
+	    flp = nextflp;
+	    fip = NULL;
+	    for ( i = 2; i < 5; ++i ) {
+		tok[ i - 2 ] = tok[ i ];
+	    }
+	    /* fall through */
+
+	case 2:
+	case 3:		/* filter, desc, and optional search scope */
+	    if ( nextflp != NULL ) { /* add to info list */
+		if (( nextfip = (LDAPFiltInfo *)NSLDAPI_CALLOC( 1,
+			sizeof( LDAPFiltInfo ))) == NULL ) {
+		    ldap_getfilter_free( lfdp );
+		    nsldapi_free_strarray( tok );
+		    return( NULL );
+		}
+		if ( fip == NULL ) {	/* first one */
+		    nextflp->lfl_ilist = nextfip;
+		} else {
+		    fip->lfi_next = nextfip;
+		}
+		fip = nextfip;
+		nextfip->lfi_next = NULL;
+		nextfip->lfi_filter = tok[ 0 ];
+		nextfip->lfi_desc = tok[ 1 ];
+		if ( tok[ 2 ] != NULL ) {
+		    if ( strcasecmp( tok[ 2 ], "subtree" ) == 0 ) {
+			nextfip->lfi_scope = LDAP_SCOPE_SUBTREE;
+		    } else if ( strcasecmp( tok[ 2 ], "onelevel" ) == 0 ) {
+			nextfip->lfi_scope = LDAP_SCOPE_ONELEVEL;
+		    } else if ( strcasecmp( tok[ 2 ], "base" ) == 0 ) {
+			nextfip->lfi_scope = LDAP_SCOPE_BASE;
+		    } else {
+			nsldapi_free_strarray( tok );
+			ldap_getfilter_free( lfdp );
+			return( NULL );
+		    }
+		    NSLDAPI_FREE( tok[ 2 ] );
+		    tok[ 2 ] = NULL;
+		} else {
+		    nextfip->lfi_scope = LDAP_SCOPE_SUBTREE;	/* default */
+		}
+		nextfip->lfi_isexact = ( strchr( tok[ 0 ], '*' ) == NULL &&
+			strchr( tok[ 0 ], '~' ) == NULL );
+		NSLDAPI_FREE( tok );
+	    }
+	    break;
+
+	default:
+	    nsldapi_free_strarray( tok );
+	    ldap_getfilter_free( lfdp );
+	    return( NULL );
+	}
+    }
+
+    if ( tag != NULL ) {
+	NSLDAPI_FREE( tag );
+    }
+
+    return( lfdp );
+}
+
+
+int
+LDAP_CALL
+ldap_set_filter_additions( LDAPFiltDesc *lfdp, char *prefix, char *suffix )
+{
+    if ( lfdp == NULL ) {
+	return( LDAP_PARAM_ERROR );
+    }
+
+    if ( lfdp->lfd_filtprefix != NULL ) {
+	NSLDAPI_FREE( lfdp->lfd_filtprefix );
+    }
+    lfdp->lfd_filtprefix = ( prefix == NULL ) ? NULL : nsldapi_strdup( prefix );
+
+    if ( lfdp->lfd_filtsuffix != NULL ) {
+	NSLDAPI_FREE( lfdp->lfd_filtsuffix );
+    }
+    lfdp->lfd_filtsuffix = ( suffix == NULL ) ? NULL : nsldapi_strdup( suffix );
+
+    return( LDAP_SUCCESS );
+}
+
+
+/*
+ * ldap_setfilteraffixes() is deprecated -- use ldap_set_filter_additions()
+ */
+void
+LDAP_CALL
+ldap_setfilteraffixes( LDAPFiltDesc *lfdp, char *prefix, char *suffix )
+{
+    (void)ldap_set_filter_additions( lfdp, prefix, suffix );
+}
+
+
+LDAPFiltInfo *
+LDAP_CALL
+ldap_getfirstfilter( LDAPFiltDesc *lfdp, char *tagpat, char *value )
+{
+    LDAPFiltList	*flp;
+
+    if ( lfdp == NULL || tagpat == NULL || value == NULL ) {
+	return( NULL );	/* punt */
+    }
+
+    if ( lfdp->lfd_curvalcopy != NULL ) {
+	NSLDAPI_FREE( lfdp->lfd_curvalcopy );
+	NSLDAPI_FREE( lfdp->lfd_curvalwords );
+    }
+
+    NSLDAPI_FREE(lfdp->lfd_curval);
+    if ((lfdp->lfd_curval = nsldapi_strdup(value)) == NULL) {
+	return( NULL );
+    }
+
+    lfdp->lfd_curfip = NULL;
+
+    for ( flp = lfdp->lfd_filtlist; flp != NULL; flp = flp->lfl_next ) {
+	if ( re_comp( tagpat ) == NULL && re_exec( flp->lfl_tag ) == 1
+		&& re_comp( flp->lfl_pattern ) == NULL
+		&& re_exec( lfdp->lfd_curval ) == 1 ) {
+	    lfdp->lfd_curfip = flp->lfl_ilist;
+	    break;
+	}
+    }
+
+    if ( lfdp->lfd_curfip == NULL ) {
+	return( NULL );
+    }
+
+    if (( lfdp->lfd_curvalcopy = nsldapi_strdup( value )) == NULL ) {
+	return( NULL );
+    }
+
+    if ( break_into_words( lfdp->lfd_curvalcopy, flp->lfl_delims,
+		&lfdp->lfd_curvalwords ) < 0 ) {
+	NSLDAPI_FREE( lfdp->lfd_curvalcopy );
+	lfdp->lfd_curvalcopy = NULL;
+	return( NULL );
+    }
+
+    return( ldap_getnextfilter( lfdp ));
+}
+
+
+LDAPFiltInfo *
+LDAP_CALL
+ldap_getnextfilter( LDAPFiltDesc *lfdp )
+{
+    LDAPFiltInfo	*fip;
+
+    if ( lfdp == NULL || ( fip = lfdp->lfd_curfip ) == NULL ) {
+	return( NULL );
+    }
+
+    lfdp->lfd_curfip = fip->lfi_next;
+
+    ldap_build_filter( lfdp->lfd_filter, LDAP_FILT_MAXSIZ, fip->lfi_filter,
+	    lfdp->lfd_filtprefix, lfdp->lfd_filtsuffix, NULL,
+	    lfdp->lfd_curval, lfdp->lfd_curvalwords );
+    lfdp->lfd_retfi.lfi_filter = lfdp->lfd_filter;
+    lfdp->lfd_retfi.lfi_desc = fip->lfi_desc;
+    lfdp->lfd_retfi.lfi_scope = fip->lfi_scope;
+    lfdp->lfd_retfi.lfi_isexact = fip->lfi_isexact;
+
+    return( &lfdp->lfd_retfi );
+}
+
+
+static char*
+filter_add_strn( char *f, char *flimit, char *v, size_t vlen )
+     /* Copy v into f.  If flimit is too small, return NULL;
+      * otherwise return (f + vlen).
+      */
+{
+    auto size_t flen = flimit - f;
+    if ( vlen > flen ) { /* flimit is too small */
+	if ( flen > 0 ) SAFEMEMCPY( f, v, flen );
+	return NULL;
+    }
+    if ( vlen > 0 ) SAFEMEMCPY( f, v, vlen );
+    return f + vlen;
+}
+
+static char*
+filter_add_value( char *f, char *flimit, char *v, int escape_all )
+     /* Copy v into f, but with parentheses escaped.  But only escape * and \
+      * if escape_all is non-zero so that either "*" or "\2a" can be used in
+      * v, with different meanings.
+      * If flimit is too small, return NULL; otherwise
+      * return (f + the number of bytes copied).
+      */
+{
+    auto char x[4];
+    auto size_t slen;
+    while ( f && *v ) {
+	switch ( *v ) {
+	case '*':
+	    if ( escape_all ) {
+		f = filter_add_strn( f, flimit, "\\2a", 3 );
+		v++;
+	    } else {
+		if ( f < flimit ) {
+		    *f++ = *v++;
+		} else {
+		    f = NULL; /* overflow */
+		}
+	    }
+	    break;
+
+	case '(':
+	case ')':
+	    sprintf( x, "\\%02x", (unsigned)*v );
+	    f = filter_add_strn( f, flimit, x, 3 );
+	    v++;
+	    break;
+
+	case '\\':
+	    if ( escape_all ) {
+		f = filter_add_strn( f, flimit, "\\5c", 3 );
+		v++;
+	    } else {
+		slen = (ldap_utf8isxdigit( v+1 ) &&
+			ldap_utf8isxdigit( v+2 )) ? 3 : (v[1] ? 2 : 1);
+		f = filter_add_strn( f, flimit, v, slen );
+		v += slen;
+	    }
+	    break;
+	    
+	default:
+	    if ( f < flimit ) {
+		*f++ = *v++;
+	    } else {
+		f = NULL; /* overflow */
+	    }
+	    break;
+	}
+    }
+    return f;
+}
+
+int
+LDAP_CALL
+ldap_create_filter( char *filtbuf, unsigned long buflen, char *pattern,
+	char *prefix, char *suffix, char *attr, char *value, char **valwords )
+{
+	char	*p, *f, *flimit;
+	int	i, wordcount, wordnum, endwordnum, escape_all;
+
+    /* 
+     * there is some confusion on what to create for a filter if 
+     * attr or value are null pointers.  For now we just leave them
+     * as TO BE DEALT with
+     */
+
+	if ( filtbuf == NULL || buflen == 0 || pattern == NULL ){
+		return( LDAP_PARAM_ERROR );
+	}
+	
+	if ( valwords == NULL ) {
+	    wordcount = 0;
+	} else {
+	    for ( wordcount = 0; valwords[ wordcount ] != NULL; ++wordcount ) {
+		;
+	    }
+	}
+
+	f = filtbuf;
+	flimit = filtbuf + buflen - 1;
+
+	if ( prefix != NULL ) {
+	    f = filter_add_strn( f, flimit, prefix, strlen( prefix ));
+	}
+
+	for ( p = pattern; f != NULL && *p != '\0'; ++p ) {
+	    if ( *p == '%' ) {
+		++p;
+		if ( *p == 'v' || *p == 'e' ) {
+		    escape_all = ( *p == 'e' );
+		    if ( ldap_utf8isdigit( p+1 )) {
+			++p;
+			wordnum = *p - '1';
+			if ( *(p+1) == '-' ) {
+			    ++p;
+			    if ( ldap_utf8isdigit( p+1 )) {
+				++p;
+				endwordnum = *p - '1';	/* e.g., "%v2-4" */
+				if ( endwordnum > wordcount - 1 ) {
+				    endwordnum = wordcount - 1;
+				}
+			    } else {
+				endwordnum = wordcount - 1;  /* e.g., "%v2-" */
+			    }
+			} else {
+			    endwordnum = wordnum;	/* e.g., "%v2" */
+			}
+
+			if ( wordcount > 0 ) {
+			    for ( i = wordnum; i <= endwordnum; ++i ) {
+				if ( i > wordnum ) {  /* add blank btw words */
+				    f = filter_add_strn( f, flimit, " ", 1 );
+				    if ( f == NULL ) break;
+				}
+				f = filter_add_value( f, flimit, valwords[ i ],
+					escape_all );
+				if ( f == NULL ) break;
+			    }
+			}
+		    } else if ( *(p+1) == '$' ) {
+			++p;
+			if ( wordcount > 0 ) {
+			    wordnum = wordcount - 1;
+			    f = filter_add_value( f, flimit,
+				    valwords[ wordnum ], escape_all );
+			}
+		    } else if ( value != NULL ) {
+			f = filter_add_value( f, flimit, value, escape_all );
+		    }
+		} else if ( *p == 'a' && attr != NULL ) {
+		    f = filter_add_strn( f, flimit, attr, strlen( attr ));
+		} else {
+		    *f++ = *p;
+		}
+	    } else {
+		*f++ = *p;
+	    }
+	    if ( f > flimit ) { /* overflow */
+		f = NULL;
+	    }
+	}
+
+	if ( suffix != NULL && f != NULL) {
+	    f = filter_add_strn( f, flimit, suffix, strlen( suffix ));
+	}
+
+	if ( f == NULL ) {
+	    *flimit = '\0';
+	    return( LDAP_SIZELIMIT_EXCEEDED );
+	}
+	*f = '\0';
+	return( LDAP_SUCCESS );
+}
+
+
+/*
+ * ldap_build_filter() is deprecated -- use ldap_create_filter() instead
+ */
+void
+LDAP_CALL
+ldap_build_filter( char *filtbuf, unsigned long buflen, char *pattern,
+	char *prefix, char *suffix, char *attr, char *value, char **valwords )
+{
+    (void)ldap_create_filter( filtbuf, buflen, pattern, prefix, suffix, attr,
+	    value, valwords );
+}
+
+
+static int
+break_into_words( char *str, char *delims, char ***wordsp )
+{
+    char	*word, **words;
+    int		count;
+    char	*lasts;
+	
+    if (( words = (char **)NSLDAPI_CALLOC( 1, sizeof( char * ))) == NULL ) {
+	return( -1 );
+    }
+    count = 0;
+    words[ count ] = NULL;
+
+    word = ldap_utf8strtok_r( str, delims, &lasts );
+    while ( word != NULL ) {
+	if (( words = (char **)NSLDAPI_REALLOC( words,
+		( count + 2 ) * sizeof( char * ))) == NULL ) {
+	    return( -1 );
+	}
+
+	words[ count ] = word;
+	words[ ++count ] = NULL;
+	word = ldap_utf8strtok_r( NULL, delims, &lasts );
+    }
+	
+    *wordsp = words;
+    return( count );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/getoption.c
@@ -0,0 +1,475 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+#include "ldap-int.h"
+
+#define LDAP_GET_BITOPT( ld, bit ) \
+	((ld)->ld_options & bit ) != 0 ? 1 : 0
+
+static int nsldapi_get_api_info( LDAPAPIInfo *aip );
+static int nsldapi_get_feature_info( LDAPAPIFeatureInfo *fip );
+
+
+int
+LDAP_CALL
+ldap_get_option( LDAP *ld, int option, void *optdata )
+{
+	int		rc = 0;
+
+	if ( !nsldapi_initialized ) {
+		nsldapi_initialize_defaults();
+	}
+
+    /*
+     * optdata MUST be a valid pointer...
+     */
+    if (NULL == optdata)
+    {
+        return(LDAP_PARAM_ERROR);
+    }
+	/*
+	 * process global options (not associated with an LDAP session handle)
+	 */
+	if ( option == LDAP_OPT_MEMALLOC_FN_PTRS ) {
+		/* struct copy */
+		*((struct ldap_memalloc_fns *)optdata) = nsldapi_memalloc_fns;
+		return( 0 );
+	}
+
+	if ( option == LDAP_OPT_API_INFO ) {
+		rc = nsldapi_get_api_info( (LDAPAPIInfo *)optdata );
+		if ( rc != LDAP_SUCCESS ) {
+			if ( ld != NULL ) {
+				LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+			}
+			return( -1 );
+		}
+		return( 0 );
+	}
+    /* 
+     * LDAP_OPT_DEBUG_LEVEL is global 
+     */
+    if (LDAP_OPT_DEBUG_LEVEL == option) 
+    {
+#ifdef LDAP_DEBUG	  
+        *((int *) optdata) = ldap_debug;
+#endif /* LDAP_DEBUG */
+        return ( 0 );
+    }
+
+	/*
+	 * if ld is NULL, arrange to return options from our default settings
+	 */
+	if ( ld == NULL ) {
+		ld = &nsldapi_ld_defaults;
+	}
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( -1 );	/* punt */
+	}
+
+
+	if (ld != &nsldapi_ld_defaults)
+		LDAP_MUTEX_LOCK( ld, LDAP_OPTION_LOCK );
+	switch( option ) {
+#ifdef LDAP_DNS
+	case LDAP_OPT_DNS:
+		*((int *) optdata) = LDAP_GET_BITOPT( ld, LDAP_BITOPT_DNS );
+		break;
+#endif
+
+	case LDAP_OPT_REFERRALS:
+		*((int *) optdata) =
+		    LDAP_GET_BITOPT( ld, LDAP_BITOPT_REFERRALS );
+		break;
+
+	case LDAP_OPT_SSL:
+		*((int *) optdata) = LDAP_GET_BITOPT( ld, LDAP_BITOPT_SSL );
+		break;
+
+	case LDAP_OPT_RESTART:
+		*((int *) optdata) = LDAP_GET_BITOPT( ld, LDAP_BITOPT_RESTART );
+		break;
+
+	case LDAP_OPT_RECONNECT:
+		*((int *) optdata) =
+		    LDAP_GET_BITOPT( ld, LDAP_BITOPT_RECONNECT );
+		break;
+
+	case LDAP_OPT_NOREBIND:
+		*((int *) optdata) =
+		    LDAP_GET_BITOPT( ld, LDAP_BITOPT_NOREBIND );
+		break;
+
+#ifdef LDAP_ASYNC_IO
+	case LDAP_OPT_ASYNC_CONNECT:
+		*((int *) optdata) =
+		    LDAP_GET_BITOPT( ld, LDAP_BITOPT_ASYNC );
+		break;
+#endif /* LDAP_ASYNC_IO */
+
+        /* stuff in the sockbuf */
+        case LDAP_X_OPT_SOCKBUF:
+                *((Sockbuf **) optdata) = ld->ld_sbp;
+                break;
+
+	case LDAP_OPT_DESC:
+		if ( ber_sockbuf_get_option( ld->ld_sbp,
+		    LBER_SOCKBUF_OPT_DESC, optdata ) != 0 ) {
+			LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL, NULL );
+			rc = -1;
+		}
+		break;
+
+	/* fields in the LDAP structure */
+	case LDAP_OPT_DEREF:
+		*((int *) optdata) = ld->ld_deref;
+		break;
+	case LDAP_OPT_SIZELIMIT:
+		*((int *) optdata) = ld->ld_sizelimit;
+                break;  
+	case LDAP_OPT_TIMELIMIT:
+		*((int *) optdata) = ld->ld_timelimit;
+                break;
+	case LDAP_OPT_REFERRAL_HOP_LIMIT:
+		 *((int *) optdata) = ld->ld_refhoplimit;
+		break;
+	case LDAP_OPT_PROTOCOL_VERSION:
+		 *((int *) optdata) = ld->ld_version;
+		break;
+	case LDAP_OPT_SERVER_CONTROLS:
+		/* fall through */
+	case LDAP_OPT_CLIENT_CONTROLS:
+		*((LDAPControl ***)optdata) = NULL;
+		/* nsldapi_dup_controls returns -1 and sets lderrno on error */
+		rc = nsldapi_dup_controls( ld, (LDAPControl ***)optdata,
+		    ( option == LDAP_OPT_SERVER_CONTROLS ) ?
+		    ld->ld_servercontrols : ld->ld_clientcontrols );
+		break;
+
+	/* rebind proc */
+	case LDAP_OPT_REBIND_FN:
+		*((LDAP_REBINDPROC_CALLBACK **) optdata) = ld->ld_rebind_fn;
+		break;
+	case LDAP_OPT_REBIND_ARG:
+		*((void **) optdata) = ld->ld_rebind_arg;
+		break;
+
+	/* i/o function pointers */
+	case LDAP_OPT_IO_FN_PTRS:
+		if ( ld->ld_io_fns_ptr == NULL ) {
+			memset( optdata, 0, sizeof( struct ldap_io_fns ));
+		} else {
+			/* struct copy */
+			*((struct ldap_io_fns *)optdata) = *(ld->ld_io_fns_ptr);
+		}
+		break;
+
+	/* extended i/o function pointers */
+	case LDAP_X_OPT_EXTIO_FN_PTRS:
+	  if ( ((struct ldap_x_ext_io_fns *) optdata)->lextiof_size == LDAP_X_EXTIO_FNS_SIZE_REV0) {
+	    ((struct ldap_x_ext_io_fns_rev0 *) optdata)->lextiof_close = ld->ld_extclose_fn;
+	    ((struct ldap_x_ext_io_fns_rev0 *) optdata)->lextiof_connect = ld->ld_extconnect_fn;
+	    ((struct ldap_x_ext_io_fns_rev0 *) optdata)->lextiof_read = ld->ld_extread_fn;
+	    ((struct ldap_x_ext_io_fns_rev0 *) optdata)->lextiof_write = ld->ld_extwrite_fn;
+	    ((struct ldap_x_ext_io_fns_rev0 *) optdata)->lextiof_poll = ld->ld_extpoll_fn;
+	    ((struct ldap_x_ext_io_fns_rev0 *) optdata)->lextiof_newhandle = ld->ld_extnewhandle_fn;
+	    ((struct ldap_x_ext_io_fns_rev0 *) optdata)->lextiof_disposehandle = ld->ld_extdisposehandle_fn;
+	    ((struct ldap_x_ext_io_fns_rev0 *) optdata)->lextiof_session_arg = ld->ld_ext_session_arg;
+	  } else if ( ((struct ldap_x_ext_io_fns *) optdata)->lextiof_size ==
+		      LDAP_X_EXTIO_FNS_SIZE ) {
+	    /* struct copy */
+	    *((struct ldap_x_ext_io_fns *) optdata) = ld->ld_ext_io_fns;
+	  } else {       
+	    LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+	    rc = -1;
+	  }
+	  break;
+	  
+	/* get socketargp in extended i/o function */
+	case LDAP_X_OPT_SOCKETARG:
+	  if ( ber_sockbuf_get_option( ld->ld_sbp,LBER_SOCKBUF_OPT_SOCK_ARG, optdata)	    
+		 != 0 ) {
+		LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL, NULL );
+		rc = -1;
+	   }
+	   	break;
+
+	/* thread function pointers */
+	case LDAP_OPT_THREAD_FN_PTRS:
+		/* struct copy */
+		*((struct ldap_thread_fns *) optdata) = ld->ld_thread;
+		break;
+
+	/* extra thread function pointers */
+	case LDAP_OPT_EXTRA_THREAD_FN_PTRS:
+		/* struct copy */
+		*((struct ldap_extra_thread_fns *) optdata) = ld->ld_thread2;
+		break;
+
+	/* DNS function pointers */
+	case LDAP_OPT_DNS_FN_PTRS:
+		/* struct copy */
+		*((struct ldap_dns_fns *) optdata) = ld->ld_dnsfn;
+		break;
+
+	/* cache function pointers */
+	case LDAP_OPT_CACHE_FN_PTRS:
+		/* struct copy */
+		*((struct ldap_cache_fns *) optdata) = ld->ld_cache;
+		break;
+	case LDAP_OPT_CACHE_STRATEGY:
+		*((int *) optdata) = ld->ld_cache_strategy;
+		break;
+	case LDAP_OPT_CACHE_ENABLE:
+		*((int *) optdata) = ld->ld_cache_on;
+		break;
+
+	case LDAP_OPT_ERROR_NUMBER:
+		*((int *) optdata) = LDAP_GET_LDERRNO( ld, NULL, NULL );
+		break;
+
+	case LDAP_OPT_ERROR_STRING:
+		(void)LDAP_GET_LDERRNO( ld, NULL, (char **)optdata );
+		*((char **) optdata) = nsldapi_strdup( *((char **) optdata ));
+		break;
+
+	case LDAP_OPT_MATCHED_DN:
+		(void)LDAP_GET_LDERRNO( ld, (char **)optdata, NULL );
+		*((char **) optdata) = nsldapi_strdup( *((char **) optdata ));
+		break;
+
+	case LDAP_OPT_PREFERRED_LANGUAGE:
+		if ( NULL != ld->ld_preferred_language ) {
+			*((char **) optdata) =
+			    nsldapi_strdup(ld->ld_preferred_language);
+		} else {
+			*((char **) optdata) = NULL;
+		}
+		break;
+
+	case LDAP_OPT_API_FEATURE_INFO:
+		rc = nsldapi_get_feature_info( (LDAPAPIFeatureInfo *)optdata );
+		if ( rc != LDAP_SUCCESS ) {
+			LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+			rc = -1;
+		}
+		break;
+
+	case LDAP_OPT_HOST_NAME:
+		*((char **) optdata) = nsldapi_strdup( ld->ld_defhost );
+		break;
+
+        case LDAP_X_OPT_CONNECT_TIMEOUT:
+                *((int *) optdata) = ld->ld_connect_timeout;
+                break;
+
+#ifdef LDAP_SASLIO_HOOKS
+	/* SASL options */
+	case LDAP_OPT_X_SASL_MECH:
+		*((char **) optdata) = nsldapi_strdup(ld->ld_def_sasl_mech);
+		break;
+	case LDAP_OPT_X_SASL_REALM:
+		*((char **) optdata) = nsldapi_strdup(ld->ld_def_sasl_realm);
+		break;
+	case LDAP_OPT_X_SASL_AUTHCID:
+		*((char **) optdata) = nsldapi_strdup(ld->ld_def_sasl_authcid);
+		break;
+	case LDAP_OPT_X_SASL_AUTHZID:
+		*((char **) optdata) = nsldapi_strdup(ld->ld_def_sasl_authzid);
+		break;
+	case LDAP_OPT_X_SASL_SSF:
+		{
+			int sc;
+			sasl_ssf_t      *ssf;
+			sasl_conn_t     *ctx;
+			if( ld->ld_defconn == NULL ) {
+				return -1;
+			}
+			ctx = (sasl_conn_t *)(ld->ld_defconn->lconn_sasl_ctx);
+			if ( ctx == NULL ) {
+				return -1;
+			}
+			sc = sasl_getprop( ctx, SASL_SSF, (const void **) &ssf );
+			if ( sc != SASL_OK ) {
+				return -1;
+			}
+			*((sasl_ssf_t *) optdata) = *ssf;
+		}
+		break;
+	case LDAP_OPT_X_SASL_SSF_MIN:
+		*((sasl_ssf_t *) optdata) = ld->ld_sasl_secprops.min_ssf;
+		break;
+	case LDAP_OPT_X_SASL_SSF_MAX:
+		*((sasl_ssf_t *) optdata) = ld->ld_sasl_secprops.max_ssf;
+		break;
+	case LDAP_OPT_X_SASL_MAXBUFSIZE:
+		*((sasl_ssf_t *) optdata) = ld->ld_sasl_secprops.maxbufsize;
+		break;
+	case LDAP_OPT_X_SASL_SSF_EXTERNAL:
+	case LDAP_OPT_X_SASL_SECPROPS:
+		/*
+		 * These options are write only.  Making these options
+		 * read/write would expose semi-private interfaces of libsasl
+		 * for which there are no cross platform/standardized
+		 * definitions.
+		 */
+		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+		rc = -1;
+		break;
+#endif
+
+	default:
+		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+		rc = -1;
+	}
+	if (ld != &nsldapi_ld_defaults)
+		LDAP_MUTEX_UNLOCK( ld, LDAP_OPTION_LOCK  );
+	return( rc );
+}
+
+
+/*
+ * Table of extended API features we support.
+ * The first field is the version of the info. strcuture itself; we do not
+ * use the ones from this table so it is okay to leave as zero.
+ */
+static LDAPAPIFeatureInfo nsldapi_extensions[] = {
+    { 0, "SERVER_SIDE_SORT",		LDAP_API_FEATURE_SERVER_SIDE_SORT },
+    { 0, "VIRTUAL_LIST_VIEW",		LDAP_API_FEATURE_VIRTUAL_LIST_VIEW },
+    { 0, "PERSISTENT_SEARCH",		LDAP_API_FEATURE_PERSISTENT_SEARCH },
+    { 0, "PROXY_AUTHORIZATION",		LDAP_API_FEATURE_PROXY_AUTHORIZATION },
+    { 0, "X_LDERRNO",			LDAP_API_FEATURE_X_LDERRNO },
+    { 0, "X_MEMCACHE",			LDAP_API_FEATURE_X_MEMCACHE },
+    { 0, "X_IO_FUNCTIONS",		LDAP_API_FEATURE_X_IO_FUNCTIONS },
+    { 0, "X_EXTIO_FUNCTIONS",		LDAP_API_FEATURE_X_EXTIO_FUNCTIONS },
+    { 0, "X_DNS_FUNCTIONS",		LDAP_API_FEATURE_X_DNS_FUNCTIONS },
+    { 0, "X_MEMALLOC_FUNCTIONS",	LDAP_API_FEATURE_X_MEMALLOC_FUNCTIONS },
+    { 0, "X_THREAD_FUNCTIONS",		LDAP_API_FEATURE_X_THREAD_FUNCTIONS },
+    { 0, "X_EXTHREAD_FUNCTIONS",	LDAP_API_FEATURE_X_EXTHREAD_FUNCTIONS },
+    { 0, "X_GETLANGVALUES",		LDAP_API_FEATURE_X_GETLANGVALUES },
+    { 0, "X_CLIENT_SIDE_SORT",		LDAP_API_FEATURE_X_CLIENT_SIDE_SORT },
+    { 0, "X_URL_FUNCTIONS",		LDAP_API_FEATURE_X_URL_FUNCTIONS },
+    { 0, "X_FILTER_FUNCTIONS",		LDAP_API_FEATURE_X_FILTER_FUNCTIONS },
+};
+
+#define NSLDAPI_EXTENSIONS_COUNT	\
+	(sizeof(nsldapi_extensions)/sizeof(LDAPAPIFeatureInfo))
+
+/*
+ * Retrieve information about this implementation of the LDAP API.
+ * Returns an LDAP error code.
+ */
+static int
+nsldapi_get_api_info( LDAPAPIInfo *aip )
+{
+	int	i;
+
+	if ( aip == NULL ) {
+		return( LDAP_PARAM_ERROR );
+	}
+
+	aip->ldapai_api_version = LDAP_API_VERSION;
+
+	if ( aip->ldapai_info_version != LDAP_API_INFO_VERSION ) {
+		aip->ldapai_info_version = LDAP_API_INFO_VERSION;
+		return( LDAP_PARAM_ERROR );
+	}
+
+	aip->ldapai_protocol_version = LDAP_VERSION_MAX;
+	aip->ldapai_vendor_version = LDAP_VENDOR_VERSION;
+
+	if (( aip->ldapai_vendor_name = nsldapi_strdup( LDAP_VENDOR_NAME ))
+	    == NULL ) {
+		return( LDAP_NO_MEMORY );
+	}
+
+	if ( NSLDAPI_EXTENSIONS_COUNT < 1 ) {
+		aip->ldapai_extensions = NULL;
+	} else {
+		if (( aip->ldapai_extensions = NSLDAPI_CALLOC(
+		    NSLDAPI_EXTENSIONS_COUNT + 1, sizeof(char *))) == NULL ) {
+			NSLDAPI_FREE( aip->ldapai_vendor_name );
+			aip->ldapai_vendor_name = NULL;
+			return( LDAP_NO_MEMORY );
+		}
+
+		for ( i = 0; i < NSLDAPI_EXTENSIONS_COUNT; ++i ) {
+			if (( aip->ldapai_extensions[i] = nsldapi_strdup(
+			    nsldapi_extensions[i].ldapaif_name )) == NULL ) {
+				ldap_value_free( aip->ldapai_extensions );
+				NSLDAPI_FREE( aip->ldapai_vendor_name );
+				aip->ldapai_extensions = NULL;
+				aip->ldapai_vendor_name = NULL;
+				return( LDAP_NO_MEMORY );
+			}
+		}
+	}
+
+	return( LDAP_SUCCESS );
+}
+
+
+/*
+ * Retrieves information about a specific extended feature of the LDAP API/
+ * Returns an LDAP error code.
+ */
+static int
+nsldapi_get_feature_info( LDAPAPIFeatureInfo *fip )
+{
+	int	i;
+
+	if ( fip == NULL || fip->ldapaif_name == NULL ) {
+		return( LDAP_PARAM_ERROR );
+	}
+
+	if ( fip->ldapaif_info_version != LDAP_FEATURE_INFO_VERSION ) {
+		fip->ldapaif_info_version = LDAP_FEATURE_INFO_VERSION;
+		return( LDAP_PARAM_ERROR );
+	}
+
+	for ( i = 0; i < NSLDAPI_EXTENSIONS_COUNT; ++i ) {
+		if ( strcmp( fip->ldapaif_name,
+		    nsldapi_extensions[i].ldapaif_name ) == 0 ) {
+			fip->ldapaif_version =
+			    nsldapi_extensions[i].ldapaif_version;
+			break;
+		}
+	}
+
+	return(( i < NSLDAPI_EXTENSIONS_COUNT ) ? LDAP_SUCCESS
+	    : LDAP_PARAM_ERROR );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/getvalues.c
@@ -0,0 +1,480 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ *  Copyright (c) 1990 Regents of the University of Michigan.
+ *  All rights reserved.
+ */
+/*
+ *  getvalues.c
+ */
+
+#if 0
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+
+static void **
+internal_ldap_get_values( LDAP *ld, LDAPMessage *entry, const char *target,
+	int lencall )
+{
+	struct berelement	ber;
+	char		        *attr;
+	int			        rc;
+	void			    **vals;
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_get_values\n", 0, 0, 0 );
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( NULL );	/* punt */
+	}
+	if ( target == NULL ||
+	    !NSLDAPI_VALID_LDAPMESSAGE_ENTRY_POINTER( entry )) {
+		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+		return( NULL );
+	}
+
+	ber = *entry->lm_ber;
+
+	/* skip sequence, dn, sequence of, and snag the first attr */
+	if ( ber_scanf( &ber, "{x{{a", &attr ) == LBER_ERROR ) {
+		LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
+		return( NULL );
+	}
+
+	rc = strcasecmp( (char *)target, attr );
+	NSLDAPI_FREE( attr );
+	if ( rc != 0 ) {
+		while ( 1 ) {
+			if ( ber_scanf( &ber, "x}{a", &attr ) == LBER_ERROR ) {
+				LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR,
+				    NULL, NULL );
+				return( NULL );
+			}
+
+			rc = strcasecmp( (char *)target, attr );
+			if ( rc == 0 ) {
+				NSLDAPI_FREE( attr );
+				break;
+			}
+			NSLDAPI_FREE( attr );
+		}
+	}
+
+	/* 
+	 * if we get this far, we've found the attribute and are sitting
+	 * just before the set of values.
+	 */
+
+	if ( lencall ) {
+		rc = ber_scanf( &ber, "[V]", &vals );
+	} else {
+		rc = ber_scanf( &ber, "[v]", &vals );
+	}
+
+	if ( rc == LBER_ERROR ) {
+		rc = LDAP_DECODING_ERROR;
+	} else {
+		rc = LDAP_SUCCESS;
+	}
+
+	LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+
+	return(( rc == LDAP_SUCCESS ) ? vals : NULL );
+}
+
+
+/* For language-sensitive attribute matching, we are looking for a
+   language tag that looks like one of the following:
+
+   cn
+   cn;lang-en
+   cn;lang-en-us
+   cn;lang-ja
+   cn;lang-ja-JP-kanji
+
+   The base language specification consists of two letters following
+   "lang-". After that, there may be additional language-specific
+   narrowings preceded by a "-". In our processing we go from the
+   specific to the general, preferring a complete subtype match, but
+   accepting a partial one. For example:
+
+   For a request for "cn;lang-en-us", we would return cn;lang-en-us
+   if present, otherwise cn;lang-en if present, otherwise cn.
+
+   Besides the language subtype, there may be other subtypes:
+
+   cn;lang-ja;binary         (Unlikely!)
+   cn;lang-ja;phonetic
+
+   If not in the target, they are ignored. If they are in the target,
+   they must be in the attribute to match.
+*/
+#define LANG_SUBTYPE_INDEX_NONE      -1
+#define LANG_SUBTYPE_INDEX_DUPLICATE -2
+
+typedef struct {
+	int    start;
+	int    length;
+} _SubStringIndex;
+
+static int
+parse_subtypes( const char *target, int *baseLenp, char **langp,
+				_SubStringIndex **subs, int *nsubtypes )
+{
+	int nSubtypes = 0;
+	int ind = 0;
+	char *nextToken;
+ 	_SubStringIndex *result = NULL;
+	int langIndex;
+	int targetLen;
+	int subtypeStart;
+
+	langIndex = LANG_SUBTYPE_INDEX_NONE;
+	*subs = NULL;
+	*langp = NULL;
+	*baseLenp = 0;
+	*nsubtypes = 0;
+	targetLen = strlen( target );
+
+	/* Parse past base attribute */
+	nextToken = strchr( target, ';' );
+	if ( NULL != nextToken ) {
+		subtypeStart = nextToken - target + 1;
+		*baseLenp = subtypeStart - 1;
+	}
+	else {
+		subtypeStart = targetLen;
+		*baseLenp = subtypeStart;
+	}
+	ind = subtypeStart;
+
+	/* How many subtypes? */
+	nextToken = (char *)target + subtypeStart;
+	while ( nextToken && *nextToken ) {
+		char *thisToken = nextToken;
+		nextToken = strchr( thisToken, ';' );
+		if ( NULL != nextToken )
+			nextToken++;
+		if ( 0 == strncasecmp( thisToken, "lang-", 5 ) ) {
+			/* If there was a previous lang tag, this is illegal! */
+			if ( langIndex != LANG_SUBTYPE_INDEX_NONE ) {
+				langIndex = LANG_SUBTYPE_INDEX_DUPLICATE;
+				return langIndex;
+			}
+			else {
+				langIndex = nSubtypes;
+			}
+		} else {
+			nSubtypes++;
+		}
+	}
+	/* No language subtype? */
+	if ( langIndex < 0 )
+		return langIndex;
+
+	/* Allocate array of non-language subtypes */
+	if ( nSubtypes > 0 ) {
+		result = (_SubStringIndex *)NSLDAPI_MALLOC( sizeof(*result)
+		    * nSubtypes );
+		memset( result, 0, sizeof(*result) * nSubtypes );
+	}
+	ind = 0;
+	nSubtypes = 0;
+	ind = subtypeStart;
+	nextToken = (char *)target + subtypeStart;
+	while ( nextToken && *nextToken ) {
+		char *thisToken = nextToken;
+		int len;
+		nextToken = strchr( thisToken, ';' );
+		if ( NULL != nextToken ) {
+			len = nextToken - thisToken;
+			nextToken++;
+		}
+		else {
+			nextToken = (char *)target + targetLen;
+			len = nextToken - thisToken;
+		}
+		if ( 0 == strncasecmp( thisToken, "lang-", 5 ) ) {
+			int i;
+			*langp = (char *)NSLDAPI_MALLOC( len + 1 );
+			for( i = 0; i < len; i++ )
+				(*langp)[i] = toupper( target[ind+i] );
+			(*langp)[len] = 0;
+		}
+		else {
+			result[nSubtypes].start = thisToken - target;
+			result[nSubtypes].length = len;
+			nSubtypes++;
+		}
+	}
+	*subs = result;
+	*nsubtypes = nSubtypes;
+	return langIndex;
+}
+		
+
+static int
+check_lang_match( const char *target, const char *baseTarget,
+				  _SubStringIndex *targetTypes,
+				  int ntargetTypes, char *targetLang, char *attr )
+{
+	int langIndex;
+ 	_SubStringIndex *subtypes;
+	int baseLen;
+	char *lang;
+	int nsubtypes;
+	int mismatch = 0;
+	int match = -1;
+	int i;
+
+	/* Get all subtypes in the attribute name */
+ 	langIndex = parse_subtypes( attr, &baseLen, &lang, &subtypes, &nsubtypes );
+
+	/* Check if there any required non-language subtypes which are
+	   not in this attribute */
+	for( i = 0; i < ntargetTypes; i++ ) {
+		char *t = (char *)target+targetTypes[i].start;
+		int tlen = targetTypes[i].length;
+		int j;
+		for( j = 0; j < nsubtypes; j++ ) {
+			char *a = attr + subtypes[j].start;
+			int alen = subtypes[j].length;
+			if ( (tlen == alen) && !strncasecmp( t, a, tlen ) )
+				break;
+		}
+		if ( j >= nsubtypes ) {
+			mismatch = 1;
+			break;
+		}
+	}
+	if ( mismatch ) {
+	    if ( NULL != subtypes )
+		    NSLDAPI_FREE( subtypes );
+		if ( NULL != lang )
+		    NSLDAPI_FREE( lang );
+		return -1;
+	}
+
+	/* If there was no language subtype... */
+	if ( langIndex < 0 ) {
+	    if ( NULL != subtypes )
+		    NSLDAPI_FREE( subtypes );
+		if ( NULL != lang )
+		    NSLDAPI_FREE( lang );
+		if ( LANG_SUBTYPE_INDEX_NONE == langIndex )
+			return 0;
+		else
+			return -1;
+	}
+
+	/* Okay, now check the language subtag */
+	i = 0;
+	while( targetLang[i] && lang[i] &&
+			(toupper(targetLang[i]) == toupper(lang[i])) )
+		i++;
+
+	/* The total length can't be longer than the requested subtype */
+	if ( !lang[i] || (lang[i] == ';') ) {
+		/* If the found subtype is shorter than the requested one, the next
+		   character in the requested one should be "-" */
+		if ( !targetLang[i] || (targetLang[i] == '-') )
+			match = i;
+	}
+	return match;
+}
+
+static int check_base_match( const char *target, char *attr )
+{
+    int i = 0;
+	int rc;
+	while( target[i] && attr[i] && (toupper(target[i]) == toupper(attr[i])) )
+	    i++;
+	rc = ( !target[i] && (!attr[i] || (';' == attr[i])) );
+	return rc;
+}
+
+static void **
+internal_ldap_get_lang_values( LDAP *ld, LDAPMessage *entry,
+							const char *target, char **type, int lencall )
+{
+	struct berelement	ber;
+	char		        *attr = NULL;
+	int			        rc;
+	void			    **vals = NULL;
+	int                 langIndex;
+ 	_SubStringIndex     *subtypes;
+	int                 nsubtypes;
+	char                *baseTarget = NULL;
+	int                 bestMatch = 0;
+	char                *lang = NULL;
+	int                 len;
+	int					firstAttr = 1;
+	char				*bestType = NULL;
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_get_values\n", 0, 0, 0 );
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( NULL );
+	}
+	if ( (target == NULL) ||
+	    !NSLDAPI_VALID_LDAPMESSAGE_ENTRY_POINTER( entry )) {
+		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+		return( NULL );
+	}
+
+	/* A language check was requested, so see if there really is a
+	   language subtype in the attribute spec */
+	langIndex = parse_subtypes( target, &len, &lang,
+							   &subtypes, &nsubtypes );
+	if ( langIndex < 0 ) {
+		if ( NULL != subtypes ) {
+			NSLDAPI_FREE( subtypes );
+			subtypes = NULL;
+		}
+		vals = internal_ldap_get_values( ld, entry, target, lencall );
+		if ( NULL != type )
+			*type = nsldapi_strdup( target );
+		return vals;
+	} else {
+		/* Get just the base attribute name */
+		baseTarget = (char *)NSLDAPI_MALLOC( len + 1 );
+		memcpy( baseTarget, target, len );
+		baseTarget[len] = 0;
+	}
+
+	ber = *entry->lm_ber;
+
+	/* Process all attributes in the entry */
+	while ( 1 ) {
+		int foundMatch = 0;
+		if ( NULL != attr )
+			NSLDAPI_FREE( attr );
+		if ( firstAttr ) {
+			firstAttr = 0;
+			/* skip sequence, dn, sequence of, and snag the first attr */
+			if ( ber_scanf( &ber, "{x{{a", &attr ) == LBER_ERROR ) {
+				break;
+			}
+		} else {
+			if ( ber_scanf( &ber, "{a", &attr ) == LBER_ERROR ) {
+				break;
+			}
+		}
+
+		if ( check_base_match( (const char *)baseTarget, attr ) ) {
+			int thisMatch = check_lang_match( target, baseTarget,
+											  subtypes, nsubtypes, lang, attr );
+			if ( thisMatch > bestMatch ) {
+				if ( vals )
+					NSLDAPI_FREE( vals );
+				foundMatch = 1;
+				bestMatch = thisMatch;
+				if ( NULL != bestType )
+					NSLDAPI_FREE( bestType );
+				bestType = attr;
+				attr = NULL;
+			}
+		}
+		if ( foundMatch ) {
+			if ( lencall ) {
+				rc = ber_scanf( &ber, "[V]}", &vals );
+			} else {
+				rc = ber_scanf( &ber, "[v]}", &vals );
+			}
+		} else {
+			ber_scanf( &ber, "x}" );
+		}
+	}
+
+	NSLDAPI_FREE( lang );
+	NSLDAPI_FREE( baseTarget );
+	NSLDAPI_FREE( subtypes );
+
+	if ( NULL != type )
+		*type = bestType;
+	else if ( NULL != bestType )
+		NSLDAPI_FREE( bestType );
+
+	if ( NULL == vals ) {
+		rc = LDAP_DECODING_ERROR;
+	} else {
+		rc = LDAP_SUCCESS;
+	}
+
+	LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+
+	return( vals );
+}
+
+
+char **
+LDAP_CALL
+ldap_get_values( LDAP *ld, LDAPMessage *entry, const char *target )
+{
+	return( (char **) internal_ldap_get_values( ld, entry, target, 0 ) );
+}
+
+struct berval **
+LDAP_CALL
+ldap_get_values_len( LDAP *ld, LDAPMessage *entry, const char *target )
+{
+	return( (struct berval **) internal_ldap_get_values( ld, entry, target,
+	    1 ) );
+}
+
+char **
+LDAP_CALL
+ldap_get_lang_values( LDAP *ld, LDAPMessage *entry, const char *target,
+						char **type )
+{
+	return( (char **) internal_ldap_get_lang_values( ld, entry,
+											target, type, 0 ) );
+}
+
+struct berval **
+LDAP_CALL
+ldap_get_lang_values_len( LDAP *ld, LDAPMessage *entry, const char *target,
+						char **type )
+{
+	return( (struct berval **) internal_ldap_get_lang_values( ld, entry,
+										   target, type, 1 ) );
+}
+
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/ldap-int.h
@@ -0,0 +1,888 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+#ifndef _LDAPINT_H
+#define _LDAPINT_H
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <time.h>
+#include <fcntl.h>
+#ifdef hpux
+#include <strings.h>
+#endif /* hpux */
+
+#ifdef _WINDOWS
+#  define FD_SETSIZE		256	/* number of connections we support */
+#  define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+#elif defined(macintosh)
+#include "ldap-macos.h"
+#else /* _WINDOWS */
+# include <sys/time.h>
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <netinet/in.h>
+#if !defined(XP_OS2) && !defined(XP_BEOS)
+# include <arpa/inet.h>
+#endif
+# include <netdb.h>
+#if !defined(hpux) && !defined(SUNOS4) && !defined(XP_BEOS)
+# include <sys/select.h>
+#endif /* !defined(hpux) and others */
+#endif /* _WINDOWS */
+
+#if defined(IRIX)
+#include <bstring.h>
+#endif /* IRIX */
+
+#ifdef XP_BEOS
+#define NSLDAPI_AVOID_OS_SOCKETS
+#endif
+
+#define NSLBERI_LBER_INT_FRIEND
+#ifdef macintosh
+#include "lber-int.h"
+#else /* macintosh */
+#include "../liblber/lber-int.h"
+#endif /* macintosh */
+
+#include "ldap.h"
+#include "ldaprot.h"
+#include "ldaplog.h"
+#include "portable.h"
+
+#ifdef LDAP_ASYNC_IO
+#ifdef NEED_FILIO
+#include <sys/filio.h>		/* to get FIONBIO for ioctl() call */
+#else /* NEED_FILIO */
+#if !defined( _WINDOWS) && !defined (macintosh)
+#include <sys/ioctl.h>		/* to get FIONBIO for ioctl() call */
+#endif /* _WINDOWS && macintosh */
+#endif /* NEED_FILIO */
+#endif /* LDAP_ASYNC_IO */
+
+#ifdef USE_SYSCONF
+#  include <unistd.h>
+#endif /* USE_SYSCONF */
+
+#ifdef LDAP_SASLIO_HOOKS
+#include <sasl.h>
+#define SASL_MAX_BUFF_SIZE      65536
+#define SASL_MIN_BUFF_SIZE      4096
+#endif
+
+#if !defined(_WINDOWS) && !defined(macintosh) && !defined(BSDI) && \
+    !defined(XP_OS2) && !defined(XP_BEOS) && !defined(NTO) && \
+    !defined(DARWIN)
+#define NSLDAPI_HAVE_POLL	1
+#endif
+
+/* SSL version, or 0 if not built with SSL */
+#if defined(NET_SSL)
+#  define SSL_VERSION 3
+#else
+#  define SSL_VERSION 0
+#endif
+
+
+#define LDAP_URL_URLCOLON	"URL:"
+#define LDAP_URL_URLCOLON_LEN	4
+
+#define LDAP_LDAP_REF_STR	LDAP_URL_PREFIX
+#define LDAP_LDAP_REF_STR_LEN	LDAP_URL_PREFIX_LEN
+#define LDAP_LDAPS_REF_STR	LDAPS_URL_PREFIX
+#define LDAP_LDAPS_REF_STR_LEN	LDAPS_URL_PREFIX_LEN
+
+/* default limit on nesting of referrals */
+#define LDAP_DEFAULT_REFHOPLIMIT	5
+#ifdef LDAP_DNS
+#define LDAP_DX_REF_STR		"dx://"
+#define LDAP_DX_REF_STR_LEN	5
+#endif /* LDAP_DNS */
+
+typedef enum { 
+    LDAP_CACHE_LOCK, 
+    LDAP_MEMCACHE_LOCK, 
+    LDAP_MSGID_LOCK,
+    LDAP_REQ_LOCK, 
+    LDAP_RESP_LOCK, 
+    LDAP_ABANDON_LOCK, 
+    LDAP_CTRL_LOCK,
+    LDAP_OPTION_LOCK, 
+    LDAP_ERR_LOCK, 
+    LDAP_CONN_LOCK, 
+    LDAP_IOSTATUS_LOCK,		/* serializes access to ld->ld_iostatus */
+    LDAP_RESULT_LOCK, 
+    LDAP_PEND_LOCK, 
+    LDAP_THREADID_LOCK, 
+#ifdef LDAP_SASLIO_HOOKS
+    LDAP_SASL_LOCK,
+#endif
+    LDAP_MAX_LOCK 
+} LDAPLock;
+
+/*
+ * This structure represents both ldap messages and ldap responses.
+ * These are really the same, except in the case of search responses,
+ * where a response has multiple messages.
+ */
+
+struct ldapmsg {
+	int		lm_msgid;	/* the message id */
+	ber_tag_t	lm_msgtype;	/* the message type */
+	BerElement	*lm_ber;	/* the ber encoded message contents */
+	struct ldapmsg	*lm_chain;	/* for search - next msg in the resp */
+	struct ldapmsg	*lm_next;	/* next response */
+	int		lm_fromcache;	/* memcache: origin of message */
+};
+
+/*
+ * structure for tracking LDAP server host, ports, DNs, etc.
+ */
+typedef struct ldap_server {
+	char			*lsrv_host;
+	char			*lsrv_dn;	/* if NULL, use default */
+	int			lsrv_port;
+	unsigned long		lsrv_options;	/* boolean options */
+#define LDAP_SRV_OPT_SECURE	0x01
+	struct ldap_server	*lsrv_next;
+} LDAPServer;
+
+/*
+ * structure for representing an LDAP server connection
+ */
+typedef struct ldap_conn {
+	Sockbuf			*lconn_sb;
+	BerElement		*lconn_ber;  /* non-NULL if in midst of msg. */
+	int			lconn_version;	/* LDAP protocol version */
+	int			lconn_refcnt;
+	unsigned long		lconn_lastused;	/* time */
+	int			lconn_status;
+#define LDAP_CONNST_CONNECTING		2
+#define LDAP_CONNST_CONNECTED		3
+#define LDAP_CONNST_DEAD		4
+	LDAPServer		*lconn_server;
+	char			*lconn_binddn;	/* DN of last successful bind */
+	int			lconn_bound;	/* has a bind been done? */
+	int			lconn_pending_requests; /* count of unsent req*/
+	char			*lconn_krbinstance;
+#ifdef LDAP_SASLIO_HOOKS
+    sasl_conn_t     *lconn_sasl_ctx; /* the sasl connection context */
+#endif /* LDAP_SASLIO_HOOKS */
+	struct ldap_conn	*lconn_next;
+} LDAPConn;
+
+
+/*
+ * structure used to track outstanding requests
+ */
+typedef struct ldapreq {
+	int		lr_msgid;	/* the message id */
+	int		lr_status;	/* status of request */
+#define LDAP_REQST_INPROGRESS	1
+#define LDAP_REQST_CHASINGREFS	2
+#define LDAP_REQST_WRITING	4
+#define LDAP_REQST_CONNDEAD	5	/* associated conn. has failed */
+	int		lr_outrefcnt;	/* count of outstanding referrals */
+	int		lr_origid;	/* original request's message id */
+	int		lr_parentcnt;	/* count of parent requests */
+	ber_tag_t	lr_res_msgtype;	/* result message type */
+	int		lr_expect_resp;	/* if non-zero, expect a response */
+	int		lr_res_errno;	/* result LDAP errno */
+	char		*lr_res_error;	/* result error string */
+	char		*lr_res_matched;/* result matched DN string */
+	BerElement	*lr_ber;	/* ber encoded request contents */
+	LDAPConn	*lr_conn;	/* connection used to send request */
+	char		*lr_binddn;	/* request is a bind for this DN */
+	struct ldapreq	*lr_parent;	/* request that spawned this referral */
+	struct ldapreq	*lr_child;	/* list of requests we spawned */
+	struct ldapreq	*lr_sibling;	/* next referral spawned */
+	struct ldapreq	*lr_prev;	/* ld->ld_requests previous request */
+	struct ldapreq	*lr_next;	/* ld->ld_requests next request */
+	LDAPControl	**lr_res_ctrls; /* result controls */
+} LDAPRequest;
+
+typedef struct ldappend {
+	void		*lp_sema;	/* semaphore to post */
+	int		lp_msgid;	/* message id */
+	LDAPMessage	*lp_result;	/* result storage */
+	struct ldappend	*lp_prev;	/* previous pending */
+	struct ldappend	*lp_next;	/* next pending */
+} LDAPPend;
+
+/*
+ * forward declaration for I/O status structure (defined in os-ip.c)
+ */
+typedef struct nsldapi_iostatus_info NSLDAPIIOStatus;
+
+/*
+ * old extended IO structure (before writev callback was added)
+ */
+struct ldap_x_ext_io_fns_rev0 {
+        int                                     lextiof_size;
+        LDAP_X_EXTIOF_CONNECT_CALLBACK          *lextiof_connect;
+        LDAP_X_EXTIOF_CLOSE_CALLBACK            *lextiof_close;
+        LDAP_X_EXTIOF_READ_CALLBACK             *lextiof_read;
+        LDAP_X_EXTIOF_WRITE_CALLBACK            *lextiof_write;
+        LDAP_X_EXTIOF_POLL_CALLBACK             *lextiof_poll;
+        LDAP_X_EXTIOF_NEWHANDLE_CALLBACK        *lextiof_newhandle;
+        LDAP_X_EXTIOF_DISPOSEHANDLE_CALLBACK    *lextiof_disposehandle;
+        void                                    *lextiof_session_arg;
+};
+#define LDAP_X_EXTIO_FNS_SIZE_REV0   sizeof(struct ldap_x_ext_io_fns_rev0)
+
+
+/*
+ * Structure representing an ldap connection.
+ *
+ * This is an opaque struct; the fields are not visible to
+ * applications that use the LDAP API.
+ */
+struct ldap {
+	struct sockbuf	*ld_sbp;	/* pointer to socket desc. & buffer */
+	char		*ld_host;
+	int		ld_version;	/* LDAP protocol version */
+	char		ld_lberoptions;
+	int		ld_deref;
+
+	int		ld_timelimit;
+	int		ld_sizelimit;
+
+	struct ldap_filt_desc	*ld_filtd;	/* from getfilter for ufn searches */
+	char		*ld_ufnprefix;	/* for incomplete ufn's */
+
+	int		ld_errno;
+	char		*ld_error;
+	char		*ld_matched;
+	int		ld_msgid;
+
+	/* Note: the ld_requests list is ordered old to new */
+	LDAPRequest	*ld_requests;	/* list of outstanding requests */
+	LDAPMessage	*ld_responses;	/* list of outstanding responses */
+	int		*ld_abandoned;	/* array of abandoned requests */
+	char		*ld_cldapdn;	/* DN used in connectionless search */
+
+	int		ld_cldaptries;	/* connectionless search retry count */
+	int		ld_cldaptimeout;/* time between retries */
+	int		ld_refhoplimit;	/* limit on referral nesting */
+	unsigned long	ld_options;	/* boolean options */
+
+#define LDAP_BITOPT_REFERRALS	0x80000000
+#define LDAP_BITOPT_SSL		0x40000000
+#define LDAP_BITOPT_DNS		0x20000000
+#define LDAP_BITOPT_RESTART	0x10000000
+#define LDAP_BITOPT_RECONNECT	0x08000000
+#define LDAP_BITOPT_ASYNC       0x04000000
+#define LDAP_BITOPT_NOREBIND    0x02000000
+
+	char		*ld_defhost;	/* full name of default server */
+	int		ld_defport;	/* port of default server */
+	BERTranslateProc ld_lber_encode_translate_proc;
+	BERTranslateProc ld_lber_decode_translate_proc;
+	LDAPConn	*ld_defconn;	/* default connection */
+	LDAPConn	*ld_conns;	/* list of all server connections */
+	NSLDAPIIOStatus	*ld_iostatus;	/* status info. about network sockets */
+	LDAP_REBINDPROC_CALLBACK *ld_rebind_fn;
+	void		*ld_rebind_arg;
+
+	/* function pointers, etc. for extended I/O */
+	struct ldap_x_ext_io_fns ld_ext_io_fns;
+#define ld_extio_size		ld_ext_io_fns.lextiof_size
+#define ld_extclose_fn		ld_ext_io_fns.lextiof_close
+#define ld_extconnect_fn	ld_ext_io_fns.lextiof_connect
+#define ld_extread_fn		ld_ext_io_fns.lextiof_read
+#define ld_extwrite_fn		ld_ext_io_fns.lextiof_write
+#define ld_extwritev_fn         ld_ext_io_fns.lextiof_writev
+#define ld_extpoll_fn		ld_ext_io_fns.lextiof_poll
+#define ld_extnewhandle_fn	ld_ext_io_fns.lextiof_newhandle
+#define ld_extdisposehandle_fn	ld_ext_io_fns.lextiof_disposehandle
+#define ld_ext_session_arg	ld_ext_io_fns.lextiof_session_arg
+
+	/* allocated pointer for older I/O functions */
+	struct ldap_io_fns	*ld_io_fns_ptr;
+#define NSLDAPI_USING_CLASSIC_IO_FUNCTIONS( ld ) ((ld)->ld_io_fns_ptr != NULL)
+
+	/* function pointers, etc. for DNS */
+	struct ldap_dns_fns	ld_dnsfn;
+#define ld_dns_extradata	ld_dnsfn.lddnsfn_extradata
+#define ld_dns_bufsize		ld_dnsfn.lddnsfn_bufsize
+#define ld_dns_gethostbyname_fn	ld_dnsfn.lddnsfn_gethostbyname
+#define ld_dns_gethostbyaddr_fn	ld_dnsfn.lddnsfn_gethostbyaddr
+#define ld_dns_getpeername_fn   ld_dnsfn.lddnsfn_getpeername
+
+	/* function pointers, etc. for threading */
+	struct ldap_thread_fns	ld_thread;
+#define ld_mutex_alloc_fn	ld_thread.ltf_mutex_alloc
+#define ld_mutex_free_fn	ld_thread.ltf_mutex_free
+#define ld_mutex_lock_fn	ld_thread.ltf_mutex_lock
+#define ld_mutex_unlock_fn	ld_thread.ltf_mutex_unlock
+#define ld_get_errno_fn		ld_thread.ltf_get_errno
+#define ld_set_errno_fn		ld_thread.ltf_set_errno
+#define ld_get_lderrno_fn	ld_thread.ltf_get_lderrno
+#define ld_set_lderrno_fn	ld_thread.ltf_set_lderrno
+#define ld_lderrno_arg		ld_thread.ltf_lderrno_arg
+	void			**ld_mutex;
+
+	/* function pointers, etc. for caching */
+	int			ld_cache_on;
+	int			ld_cache_strategy;
+	struct ldap_cache_fns	ld_cache;
+#define ld_cache_config		ld_cache.lcf_config
+#define ld_cache_bind		ld_cache.lcf_bind
+#define ld_cache_unbind		ld_cache.lcf_unbind
+#define ld_cache_search		ld_cache.lcf_search
+#define ld_cache_compare	ld_cache.lcf_compare
+#define ld_cache_add		ld_cache.lcf_add
+#define ld_cache_delete		ld_cache.lcf_delete
+#if 0
+#define ld_cache_rename		ld_cache.lcf_rename
+#endif
+#define ld_cache_modify		ld_cache.lcf_modify
+#define ld_cache_modrdn		ld_cache.lcf_modrdn
+#define ld_cache_abandon	ld_cache.lcf_abandon
+#define ld_cache_result		ld_cache.lcf_result
+#define ld_cache_flush		ld_cache.lcf_flush
+#define ld_cache_arg		ld_cache.lcf_arg
+
+	/* ldapv3 controls */
+	LDAPControl		**ld_servercontrols;
+	LDAPControl		**ld_clientcontrols;
+
+	/* Preferred language */
+	char            *ld_preferred_language;
+
+	/* MemCache */
+	LDAPMemCache	*ld_memcache;
+
+	/* Pending results */
+	LDAPPend	*ld_pend;	/* list of pending results */
+
+	/* extra thread function pointers */
+	struct ldap_extra_thread_fns	ld_thread2;
+
+	/*
+	 * With the 4.0 and later versions of the LDAP SDK, the extra thread
+	 * functions except for the ld_threadid_fn have been disabled.
+	 * Look at the release notes for the full explanation.
+	 */
+#define ld_mutex_trylock_fn		ld_thread2.ltf_mutex_trylock
+#define ld_sema_alloc_fn		ld_thread2.ltf_sema_alloc
+#define ld_sema_free_fn			ld_thread2.ltf_sema_free
+#define ld_sema_wait_fn			ld_thread2.ltf_sema_wait
+#define ld_sema_post_fn			ld_thread2.ltf_sema_post
+#define ld_threadid_fn			ld_thread2.ltf_threadid_fn
+
+	/* extra data for mutex handling in referrals */
+	void 			*ld_mutex_threadid[LDAP_MAX_LOCK];
+	unsigned long		ld_mutex_refcnt[LDAP_MAX_LOCK];
+
+	/* connect timeout value (milliseconds) */
+	int				ld_connect_timeout;
+
+#ifdef LDAP_SASLIO_HOOKS
+	/* SASL default option settings */
+	char                    *ld_def_sasl_mech;
+	char                    *ld_def_sasl_realm;
+	char                    *ld_def_sasl_authcid;
+	char                    *ld_def_sasl_authzid;
+	/* SASL Security properties */
+	struct sasl_security_properties ld_sasl_secprops;
+#endif
+};
+
+/* allocate/free mutex */
+#define LDAP_MUTEX_ALLOC( ld ) \
+	(((ld)->ld_mutex_alloc_fn != NULL) ? (ld)->ld_mutex_alloc_fn() : NULL)
+
+/* allocate/free mutex */
+#define LDAP_MUTEX_FREE( ld, m ) \
+	if ( (ld)->ld_mutex_free_fn != NULL && m != NULL ) { \
+		(ld)->ld_mutex_free_fn( m ); \
+	}
+
+/* enter/exit critical sections */
+/*
+ * The locks assume that the locks are thread safe.  XXXmcs: which means???
+ *
+ * Note that we test for both ld_mutex_lock_fn != NULL AND ld_mutex != NULL.
+ * This is necessary because there is a window in ldap_init() between the
+ * time we set the ld_mutex_lock_fn pointer and the time we allocate the
+ * mutexes in which external code COULD be called which COULD make a call to
+ * something like ldap_get_option(), which uses LDAP_MUTEX_LOCK().  The
+ * libprldap code does this in its newhandle callback (prldap_newhandle).
+ */
+
+#define LDAP_MUTEX_LOCK(ld, lock) \
+    if ((ld)->ld_mutex_lock_fn != NULL && ld->ld_mutex != NULL) { \
+        if ((ld)->ld_threadid_fn != NULL) { \
+            if ((ld)->ld_mutex_threadid[lock] == (ld)->ld_threadid_fn()) { \
+                (ld)->ld_mutex_refcnt[lock]++; \
+            } else { \
+                (ld)->ld_mutex_lock_fn(ld->ld_mutex[lock]); \
+                (ld)->ld_mutex_threadid[lock] = ld->ld_threadid_fn(); \
+                (ld)->ld_mutex_refcnt[lock] = 1; \
+            } \
+        } else { \
+            (ld)->ld_mutex_lock_fn(ld->ld_mutex[lock]); \
+        } \
+    } 
+
+#define LDAP_MUTEX_UNLOCK(ld, lock) \
+    if ((ld)->ld_mutex_lock_fn != NULL && ld->ld_mutex != NULL) { \
+        if ((ld)->ld_threadid_fn != NULL) { \
+            if ((ld)->ld_mutex_threadid[lock] == (ld)->ld_threadid_fn()) { \
+                (ld)->ld_mutex_refcnt[lock]--; \
+                if ((ld)->ld_mutex_refcnt[lock] <= 0) { \
+                    (ld)->ld_mutex_threadid[lock] = (void *) -1; \
+                    (ld)->ld_mutex_refcnt[lock] = 0; \
+                    (ld)->ld_mutex_unlock_fn(ld->ld_mutex[lock]); \
+                } \
+            } \
+        } else { \
+            ld->ld_mutex_unlock_fn(ld->ld_mutex[lock]); \
+        } \
+    }
+
+/* Backward compatibility locks */
+#define LDAP_MUTEX_BC_LOCK( ld, i ) \
+	/* the ld_mutex_trylock_fn is always set to NULL */ \
+	/* in setoption.c as the extra thread functions were */ \
+	/* turned off in the 4.0 SDK.  This check will  */ \
+	/* always be true */ \
+	if( (ld)->ld_mutex_trylock_fn == NULL ) { \
+		LDAP_MUTEX_LOCK( ld, i ) ; \
+	}
+#define LDAP_MUTEX_BC_UNLOCK( ld, i ) \
+	/* the ld_mutex_trylock_fn is always set to NULL */ \
+	/* in setoption.c as the extra thread functions were */ \
+	/* turned off in the 4.0 SDK.  This check will  */ \
+	/* always be true */ \
+	if( (ld)->ld_mutex_trylock_fn == NULL ) { \
+		LDAP_MUTEX_UNLOCK( ld, i ) ; \
+	}
+
+/* allocate/free semaphore */
+#define LDAP_SEMA_ALLOC( ld ) \
+	(((ld)->ld_sema_alloc_fn != NULL) ? (ld)->ld_sema_alloc_fn() : NULL)
+#define LDAP_SEMA_FREE( ld, m ) \
+	if ( (ld)->ld_sema_free_fn != NULL && m != NULL ) { \
+		(ld)->ld_sema_free_fn( m ); \
+	}
+
+/* wait/post binary semaphore */
+#define LDAP_SEMA_WAIT( ld, lp ) \
+	if ( (ld)->ld_sema_wait_fn != NULL ) { \
+		(ld)->ld_sema_wait_fn( lp->lp_sema ); \
+	}
+#define LDAP_SEMA_POST( ld, lp ) \
+	if ( (ld)->ld_sema_post_fn != NULL ) { \
+		(ld)->ld_sema_post_fn( lp->lp_sema ); \
+	}
+#define POST( ld, y, z ) \
+	/* the ld_mutex_trylock_fn is always set to NULL */ \
+	/* in setoption.c as the extra thread functions were */ \
+	/* turned off in the 4.0 SDK.  This check will  */ \
+	/* always be false */ \
+	if( (ld)->ld_mutex_trylock_fn != NULL ) { \
+		nsldapi_post_result( ld, y, z ); \
+	}
+
+/* get/set errno */
+#ifndef macintosh
+#define LDAP_SET_ERRNO( ld, e ) \
+	if ( (ld)->ld_set_errno_fn != NULL ) { \
+		(ld)->ld_set_errno_fn( e ); \
+	} else { \
+		errno = e; \
+	}
+#define LDAP_GET_ERRNO( ld ) \
+	(((ld)->ld_get_errno_fn != NULL) ? \
+		(ld)->ld_get_errno_fn() : errno)
+#else /* macintosh */
+#define LDAP_SET_ERRNO( ld, e ) \
+	if ( (ld)->ld_set_errno_fn != NULL ) { \
+		(ld)->ld_set_errno_fn( e ); \
+	}
+#define LDAP_GET_ERRNO( ld ) \
+	(((ld)->ld_get_errno_fn != NULL) ? \
+		(ld)->ld_get_errno_fn() : 0)
+#endif
+
+
+/* get/set ldap-specific errno */
+#define LDAP_SET_LDERRNO( ld, e, m, s )	ldap_set_lderrno( ld, e, m, s )
+#define LDAP_GET_LDERRNO( ld, m, s ) ldap_get_lderrno( ld, m, s )
+
+/*
+ * your standard "mimimum of two values" macro
+ */
+#define NSLDAPI_MIN(a, b)	(((a) < (b)) ? (a) : (b))
+
+/*
+ * handy macro to check whether LDAP struct is set up for CLDAP or not
+ */
+#define LDAP_IS_CLDAP( ld )	( ld->ld_sbp->sb_naddr > 0 )
+
+/*
+ * Some Unix error defs. Under CW 7, we can't define OTUNIXERRORS because
+ * it generates many conflicts with errno.h. Define what we need here.
+ * These need to be in sync with OpenTransport.h
+ */
+ 
+#if defined(macintosh)
+#define EWOULDBLOCK     35
+#define EHOSTUNREACH    65
+#endif
+
+/*
+ * handy macro to check errno "e" for an "in progress" sort of error
+ */
+#if defined(macintosh) || defined(_WINDOWS)
+#define NSLDAPI_ERRNO_IO_INPROGRESS( e )  ((e) == EWOULDBLOCK || (e) == EAGAIN)
+#else
+#ifdef EAGAIN
+#define NSLDAPI_ERRNO_IO_INPROGRESS( e )  ((e) == EWOULDBLOCK || (e) == EINPROGRESS || (e) == EAGAIN)
+#else /* EAGAIN */
+#define NSLDAPI_ERRNO_IO_INPROGRESS( e )  ((e) == EWOULDBLOCK || (e) == EINPROGRESS) 
+#endif /* EAGAIN */
+#endif /* macintosh || _WINDOWS*/
+
+/*
+ * macro to return the LDAP protocol version we are using
+ */
+#define NSLDAPI_LDAP_VERSION( ld )	( (ld)->ld_defconn == NULL ? \
+					(ld)->ld_version : \
+					(ld)->ld_defconn->lconn_version )
+
+/*
+ * Structures used for handling client filter lists.
+ */
+#define LDAP_FILT_MAXSIZ	1024
+
+struct ldap_filt_list {
+    char			*lfl_tag;
+    char			*lfl_pattern;
+    char			*lfl_delims;
+    struct ldap_filt_info	*lfl_ilist;
+    struct ldap_filt_list	*lfl_next;
+};
+
+struct ldap_filt_desc {
+	LDAPFiltList		*lfd_filtlist;
+	LDAPFiltInfo		*lfd_curfip;
+	LDAPFiltInfo		lfd_retfi;
+	char			lfd_filter[ LDAP_FILT_MAXSIZ ];
+	char			*lfd_curval;
+	char			*lfd_curvalcopy;
+	char			**lfd_curvalwords;
+	char			*lfd_filtprefix;
+	char			*lfd_filtsuffix;
+};
+
+/*
+ * "internal" globals used to track defaults and memory allocation callbacks:
+ *    (the actual definitions are in open.c)
+ */
+extern struct ldap			nsldapi_ld_defaults;
+extern struct ldap_memalloc_fns		nsldapi_memalloc_fns;
+extern int				nsldapi_initialized;
+
+
+/*
+ * Memory allocation done in liblber should all go through one of the
+ * following macros. This is so we can plug-in alternative memory
+ * allocators, etc. as the need arises.
+ */
+#define NSLDAPI_MALLOC( size )		ldap_x_malloc( size )
+#define NSLDAPI_CALLOC( nelem, elsize )	ldap_x_calloc( nelem, elsize )
+#define NSLDAPI_REALLOC( ptr, size )	ldap_x_realloc( ptr, size )
+#define NSLDAPI_FREE( ptr )		ldap_x_free( ptr )
+
+
+/*
+ * macros used to check validity of data structures and parameters
+ */
+#define NSLDAPI_VALID_LDAP_POINTER( ld ) \
+	( (ld) != NULL )
+
+#define NSLDAPI_VALID_LDAPMESSAGE_POINTER( lm ) \
+	( (lm) != NULL )
+
+#define NSLDAPI_VALID_LDAPMESSAGE_ENTRY_POINTER( lm ) \
+	( (lm) != NULL && (lm)->lm_msgtype == LDAP_RES_SEARCH_ENTRY )
+
+#define NSLDAPI_VALID_LDAPMESSAGE_REFERENCE_POINTER( lm ) \
+	( (lm) != NULL && (lm)->lm_msgtype == LDAP_RES_SEARCH_REFERENCE )
+
+#define NSLDAPI_VALID_LDAPMESSAGE_BINDRESULT_POINTER( lm ) \
+	( (lm) != NULL && (lm)->lm_msgtype == LDAP_RES_BIND )
+
+#define NSLDAPI_VALID_LDAPMESSAGE_EXRESULT_POINTER( lm ) \
+	( (lm) != NULL && (lm)->lm_msgtype == LDAP_RES_EXTENDED )
+
+#define NSLDAPI_VALID_LDAPMOD_ARRAY( mods ) \
+	( (mods) != NULL )
+
+#define NSLDAPI_VALID_NONEMPTY_LDAPMOD_ARRAY( mods ) \
+	( (mods) != NULL && (mods)[0] != NULL )
+
+#define NSLDAPI_IS_SEARCH_ENTRY( code ) \
+	((code) == LDAP_RES_SEARCH_ENTRY)
+
+#define NSLDAPI_IS_SEARCH_RESULT( code ) \
+	((code) == LDAP_RES_SEARCH_RESULT)
+
+#define NSLDAPI_SEARCH_RELATED_RESULT( code ) \
+	(NSLDAPI_IS_SEARCH_RESULT( code ) || NSLDAPI_IS_SEARCH_ENTRY( code ))
+
+/*
+ * in bind.c
+ */
+char *nsldapi_get_binddn( LDAP *ld );
+
+/*
+ * in cache.c
+ */
+void nsldapi_add_result_to_cache( LDAP *ld, LDAPMessage *result );
+
+/*
+ * in dsparse.c
+ */
+int nsldapi_next_line_tokens( char **bufp, long *blenp, char ***toksp );
+void nsldapi_free_strarray( char **sap );
+
+/*
+ * in error.c
+ */
+int nsldapi_parse_result( LDAP *ld, int msgtype, BerElement *rber,
+    int *errcodep, char **matchednp, char **errmsgp, char ***referralsp,
+    LDAPControl ***serverctrlsp );
+
+/*
+ * in open.c
+ */
+void nsldapi_initialize_defaults( void );
+void nsldapi_mutex_alloc_all( LDAP *ld );
+void nsldapi_mutex_free_all( LDAP *ld );
+int nsldapi_open_ldap_defconn( LDAP *ld );
+char *nsldapi_strdup( const char *s );  /* if s is NULL, returns NULL */
+
+/*
+ * in os-ip.c
+ */
+int nsldapi_connect_to_host( LDAP *ld, Sockbuf *sb, const char *host,
+	int port, int secure, char **krbinstancep );
+void nsldapi_close_connection( LDAP *ld, Sockbuf *sb );
+
+int nsldapi_iostatus_poll( LDAP *ld, struct timeval *timeout );
+void nsldapi_iostatus_free( LDAP *ld );
+int nsldapi_iostatus_interest_write( LDAP *ld, Sockbuf *sb );
+int nsldapi_iostatus_interest_read( LDAP *ld, Sockbuf *sb );
+int nsldapi_iostatus_interest_clear( LDAP *ld, Sockbuf *sb );
+int nsldapi_iostatus_is_read_ready( LDAP *ld, Sockbuf *sb );
+int nsldapi_iostatus_is_write_ready( LDAP *ld, Sockbuf *sb );
+int nsldapi_install_lber_extiofns( LDAP *ld, Sockbuf *sb );
+int nsldapi_install_compat_io_fns( LDAP *ld, struct ldap_io_fns *iofns );
+
+/*
+ * if referral.c
+ */
+int nsldapi_parse_reference( LDAP *ld, BerElement *rber, char ***referralsp,
+	LDAPControl ***serverctrlsp );
+
+
+/*
+ * in result.c
+ */
+int ldap_msgdelete( LDAP *ld, int msgid );
+int nsldapi_result_nolock( LDAP *ld, int msgid, int all, int unlock_permitted,
+    struct timeval *timeout, LDAPMessage **result );
+int nsldapi_wait_result( LDAP *ld, int msgid, int all, struct timeval *timeout,
+    LDAPMessage **result );
+int nsldapi_post_result( LDAP *ld, int msgid, LDAPMessage *result );
+
+/*
+ * in request.c
+ */
+int nsldapi_send_initial_request( LDAP *ld, int msgid, unsigned long msgtype,
+	char *dn, BerElement *ber );
+int nsldapi_send_pending_requests_nolock( LDAP *ld, LDAPConn *lc );
+int nsldapi_alloc_ber_with_options( LDAP *ld, BerElement **berp );
+void nsldapi_set_ber_options( LDAP *ld, BerElement *ber );
+int nsldapi_send_ber_message( LDAP *ld, Sockbuf *sb, BerElement *ber,
+	int freeit, int epipe_handler );
+int nsldapi_send_server_request( LDAP *ld, BerElement *ber, int msgid,
+	LDAPRequest *parentreq, LDAPServer *srvlist, LDAPConn *lc,
+	char *bindreqdn, int bind );
+LDAPConn *nsldapi_new_connection( LDAP *ld, LDAPServer **srvlistp, int use_ldsb,
+	int connect, int bind );
+LDAPRequest *nsldapi_find_request_by_msgid( LDAP *ld, int msgid );
+LDAPRequest *nsldapi_new_request( LDAPConn *lc, BerElement *ber, int msgid,
+   int expect_resp );
+void nsldapi_free_request( LDAP *ld, LDAPRequest *lr, int free_conn );
+void nsldapi_queue_request_nolock( LDAP *ld, LDAPRequest *lr );
+void nsldapi_free_connection( LDAP *ld, LDAPConn *lc,
+	LDAPControl **serverctrls, LDAPControl **clientctrls,
+	int force, int unbind );
+void nsldapi_dump_connection( LDAP *ld, LDAPConn *lconns, int all );
+void nsldapi_dump_requests_and_responses( LDAP *ld );
+int nsldapi_chase_v2_referrals( LDAP *ld, LDAPRequest *lr, char **errstrp,
+	int *totalcountp, int *chasingcountp );
+int nsldapi_chase_v3_refs( LDAP *ld, LDAPRequest *lr, char **refs,
+	int is_reference, int *totalcountp, int *chasingcountp );
+int nsldapi_append_referral( LDAP *ld, char **referralsp, char *s );
+void nsldapi_connection_lost_nolock( LDAP *ld, Sockbuf *sb );
+
+#ifdef LDAP_SASLIO_HOOKS
+/*
+ * in saslbind.c
+ */
+int nsldapi_sasl_is_inited();
+int nsldapi_sasl_cvterrno( LDAP *ld, int err, char *msg );
+int nsldapi_sasl_secprops( const char *in,
+                        sasl_security_properties_t *secprops );
+
+/*
+ * in saslio.c
+ */
+int nsldapi_sasl_install( LDAP *ld, LDAPConn *lconn );
+int nsldapi_sasl_open( LDAP *ld, LDAPConn *lconn, sasl_conn_t **ctx, sasl_ssf_t ssf );
+
+#endif /* LDAP_SASLIO_HOOKS */
+
+/*
+ * in search.c
+ */
+int nsldapi_build_search_req( LDAP *ld, const char *base, int scope,
+	const char *filter, char **attrs, int attrsonly,
+	LDAPControl **serverctrls, LDAPControl **clientctrls,
+	int timelimit, int sizelimit, int msgid, BerElement **berp );
+
+/*
+ * in unbind.c
+ */
+int ldap_ld_free( LDAP *ld, LDAPControl **serverctrls,
+	LDAPControl **clientctrls, int close );
+int nsldapi_send_unbind( LDAP *ld, Sockbuf *sb, LDAPControl **serverctrls,
+	LDAPControl **clientctrls );
+
+#ifdef LDAP_DNS
+/*
+ * in getdxbyname.c
+ */
+char **nsldapi_getdxbyname( char *domain );
+
+#endif /* LDAP_DNS */
+
+/*
+ * in unescape.c
+ */
+void nsldapi_hex_unescape( char *s );
+
+/*
+ * in compat.c
+ */
+#ifdef hpux
+char *nsldapi_compat_ctime_r( const time_t *clock, char *buf, int buflen );
+struct hostent *nsldapi_compat_gethostbyname_r( const char *name,
+	struct hostent *result, char *buffer, int buflen, int *h_errnop );
+#endif /* hpux */
+
+/*
+ * in control.c
+ */
+int nsldapi_put_controls( LDAP *ld, LDAPControl **ctrls, int closeseq,
+	BerElement *ber );
+int nsldapi_get_controls( BerElement *ber, LDAPControl ***controlsp );
+int nsldapi_find_controls( BerElement *ber, LDAPControl ***controlsp );
+int nsldapi_dup_controls( LDAP *ld, LDAPControl ***ldctrls,
+	LDAPControl **newctrls );
+int nsldapi_build_control( char *oid, BerElement *ber, int freeber,
+    char iscritical, LDAPControl **ctrlp );
+
+
+/*
+ * in url.c
+ */
+int nsldapi_url_parse( const char *inurl, LDAPURLDesc **ludpp,
+	int dn_required );
+
+
+/*
+ * in charset.c
+ *
+ * If we ever want to expose character set translation functionality to
+ * users of libldap, all of these prototypes will need to be moved to ldap.h
+ */
+#ifdef STR_TRANSLATION
+void ldap_set_string_translators( LDAP *ld,
+        BERTranslateProc encode_proc, BERTranslateProc decode_proc );
+int ldap_translate_from_t61( LDAP *ld, char **bufp,
+        unsigned long *lenp, int free_input );
+int ldap_translate_to_t61( LDAP *ld, char **bufp,
+        unsigned long *lenp, int free_input );
+void ldap_enable_translation( LDAP *ld, LDAPMessage *entry,
+        int enable );
+#ifdef LDAP_CHARSET_8859
+int ldap_t61_to_8859( char **bufp, unsigned long *buflenp,
+        int free_input );
+int ldap_8859_to_t61( char **bufp, unsigned long *buflenp,
+        int free_input );
+#endif /* LDAP_CHARSET_8859 */
+#endif /* STR_TRANSLATION */
+
+/*
+ * in memcache.h
+ */
+int ldap_memcache_createkey( LDAP *ld, const char *base, int scope,
+	const char *filter, char **attrs, int attrsonly,
+	LDAPControl **serverctrls, LDAPControl **clientctrls,
+	unsigned long *keyp );
+int ldap_memcache_result( LDAP *ld, int msgid, unsigned long key );
+int ldap_memcache_new( LDAP *ld, int msgid, unsigned long key,
+	const char *basedn );
+int ldap_memcache_append( LDAP *ld, int msgid, int bLast, LDAPMessage *result );
+int ldap_memcache_abandon( LDAP *ld, int msgid );
+
+/*
+ * in sbind.c
+ */
+void nsldapi_handle_reconnect( LDAP *ld );
+
+#endif /* _LDAPINT_H */
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/memcache.c
@@ -0,0 +1,2244 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ *
+ *  memcache.c - routines that implement an in-memory cache.
+ *
+ *  To Do:  1) ber_dup_ext().
+ *	    2) referrals and reference?
+ */
+
+#include <assert.h>
+#include "ldap-int.h"
+
+/*
+ * Extra size allocated to BerElement.
+ * XXXmcs: must match EXBUFSIZ in liblber/io.c?
+ */
+#define EXTRA_SIZE		    1024
+
+/* Mode constants for function memcache_access() */
+#define MEMCACHE_ACCESS_ADD	    0
+#define MEMCACHE_ACCESS_APPEND	    1
+#define MEMCACHE_ACCESS_APPEND_LAST 2
+#define MEMCACHE_ACCESS_FIND	    3
+#define MEMCACHE_ACCESS_DELETE	    4
+#define MEMCACHE_ACCESS_DELETE_ALL  5
+#define MEMCACHE_ACCESS_UPDATE	    6
+#define MEMCACHE_ACCESS_FLUSH	    7
+#define MEMCACHE_ACCESS_FLUSH_ALL   8
+#define MEMCACHE_ACCESS_FLUSH_LRU   9
+#define MEMCACHE_ACCESS_FLUSH_RESULTS 10
+
+/* Mode constants for function memcache_adj_size */
+#define MEMCACHE_SIZE_DEDUCT	    0
+#define MEMCACHE_SIZE_ADD	    1
+
+#define MEMCACHE_SIZE_ENTRIES       1
+#define MEMCACHE_SIZE_NON_ENTRIES   2
+
+/* Size used for calculation if given size of cache is 0 */
+#define MEMCACHE_DEF_SIZE	    131072		/* 128K bytes */
+
+/* Index into different list structure */
+#define LIST_TTL		    0
+#define LIST_LRU		    1
+#define LIST_TMP		    2
+#define LIST_TOTAL		    3
+
+/* Macros to make code more readable */
+#define NSLDAPI_VALID_MEMCACHE_POINTER( cp )	( (cp) != NULL )
+#define NSLDAPI_STR_NONNULL( s )		( (s) ? (s) : "" )
+#define NSLDAPI_SAFE_STRLEN( s )		( (s) ? strlen((s)) + 1 : 1 )
+
+/* Macros dealing with mutex */
+#define LDAP_MEMCACHE_MUTEX_LOCK( c ) \
+	if ( (c) && ((c)->ldmemc_lock_fns).ltf_mutex_lock ) { \
+	    ((c)->ldmemc_lock_fns).ltf_mutex_lock( (c)->ldmemc_lock ); \
+	}
+
+#define LDAP_MEMCACHE_MUTEX_UNLOCK( c ) \
+	if ( (c) && ((c)->ldmemc_lock_fns).ltf_mutex_unlock ) { \
+	    ((c)->ldmemc_lock_fns).ltf_mutex_unlock( (c)->ldmemc_lock ); \
+	}
+
+#define LDAP_MEMCACHE_MUTEX_ALLOC( c ) \
+	((c) && ((c)->ldmemc_lock_fns).ltf_mutex_alloc ? \
+	    ((c)->ldmemc_lock_fns).ltf_mutex_alloc() : NULL)
+
+#define LDAP_MEMCACHE_MUTEX_FREE( c ) \
+	if ( (c) && ((c)->ldmemc_lock_fns).ltf_mutex_free ) { \
+	    ((c)->ldmemc_lock_fns).ltf_mutex_free( (c)->ldmemc_lock ); \
+	}
+
+/* Macros used for triming unnecessary spaces in a basedn */
+#define NSLDAPI_IS_SPACE( c ) \
+	(((c) == ' ') || ((c) == '\t') || ((c) == '\n'))
+
+#define NSLDAPI_IS_SEPARATER( c ) \
+	((c) == ',')
+
+/* Hash table callback function pointer definition */
+typedef int (*HashFuncPtr)(int table_size, void *key);
+typedef int (*PutDataPtr)(void **ppTableData, void *key, void *pData);
+typedef int (*GetDataPtr)(void *pTableData, void *key, void **ppData);
+typedef int (*RemoveDataPtr)(void **ppTableData, void *key, void **ppData);
+typedef int (*MiscFuncPtr)(void **ppTableData, void *key, void *pData);
+typedef void (*ClrTableNodePtr)(void **ppTableData, void *pData);
+
+/* Structure of a node in a hash table */
+typedef struct HashTableNode_struct {
+    void *pData;
+} HashTableNode;
+
+/* Structure of a hash table */
+typedef struct HashTable_struct {
+    HashTableNode   *table;
+    int		    size;
+    HashFuncPtr	    hashfunc;
+    PutDataPtr	    putdata;
+    GetDataPtr	    getdata;
+    MiscFuncPtr     miscfunc;
+    RemoveDataPtr   removedata;
+    ClrTableNodePtr clrtablenode;
+} HashTable;
+
+/* Structure uniquely identifies a search request */
+typedef struct ldapmemcacheReqId_struct {
+    LDAP				*ldmemcrid_ld;
+    int					ldmemcrid_msgid;
+} ldapmemcacheReqId;
+
+/* Structure representing a ldap handle associated to memcache */
+typedef struct ldapmemcacheld_struct {
+    LDAP		    		*ldmemcl_ld;
+    struct ldapmemcacheld_struct	*ldmemcl_next;
+} ldapmemcacheld;
+
+/* Structure representing header of a search result */
+typedef struct ldapmemcacheRes_struct {
+    char				*ldmemcr_basedn;
+    unsigned long			ldmemcr_crc_key;
+    unsigned long			ldmemcr_resSize;
+    unsigned long			ldmemcr_timestamp;
+    LDAPMessage				*ldmemcr_resHead;
+    LDAPMessage				*ldmemcr_resTail;
+    ldapmemcacheReqId			ldmemcr_req_id;
+    struct ldapmemcacheRes_struct	*ldmemcr_next[LIST_TOTAL];
+    struct ldapmemcacheRes_struct	*ldmemcr_prev[LIST_TOTAL];
+    struct ldapmemcacheRes_struct	*ldmemcr_htable_next;
+} ldapmemcacheRes;
+
+/* Structure for memcache statistics */
+typedef struct ldapmemcacheStats_struct {
+    unsigned long			ldmemcstat_tries;
+    unsigned long			ldmemcstat_hits;
+} ldapmemcacheStats;
+
+/* Structure of a memcache object */
+struct ldapmemcache {
+    unsigned long			ldmemc_ttl;
+    unsigned long			ldmemc_size;
+    unsigned long			ldmemc_size_used;
+    unsigned long			ldmemc_size_entries;
+    char				**ldmemc_basedns;
+    void				*ldmemc_lock;
+    ldapmemcacheld			*ldmemc_lds;
+    HashTable				*ldmemc_resTmp;
+    HashTable				*ldmemc_resLookup;
+    ldapmemcacheRes			*ldmemc_resHead[LIST_TOTAL];
+    ldapmemcacheRes			*ldmemc_resTail[LIST_TOTAL];
+    struct ldap_thread_fns		ldmemc_lock_fns;
+    ldapmemcacheStats			ldmemc_stats;
+};
+
+/* Function prototypes */
+static int memcache_exist(LDAP *ld);
+static int memcache_add_to_ld(LDAP *ld, int msgid, LDAPMessage *pMsg);
+static int memcache_compare_dn(const char *main_dn, const char *dn, int scope);
+static int memcache_dup_message(LDAPMessage *res, int msgid, int fromcache, 
+				LDAPMessage **ppResCopy, unsigned long *pSize);
+static BerElement* memcache_ber_dup(BerElement* pBer, unsigned long *pSize);
+
+static void memcache_trim_basedn_spaces(char *basedn);
+static int memcache_validate_basedn(LDAPMemCache *cache, const char *basedn);
+static int memcache_get_ctrls_len(LDAPControl **ctrls);
+static void memcache_append_ctrls(char *buf, LDAPControl **serverCtrls,
+				  LDAPControl **clientCtrls);
+static int memcache_adj_size(LDAPMemCache *cache, unsigned long size,
+                             int usageFlags, int bAdd);
+static int memcache_free_entry(LDAPMemCache *cache, ldapmemcacheRes *pRes);
+static int memcache_expired(LDAPMemCache *cache, ldapmemcacheRes *pRes, 
+			    unsigned long curTime);
+static int memcache_add_to_list(LDAPMemCache *cache, ldapmemcacheRes *pRes, 
+				int index);
+static int memcache_add_res_to_list(ldapmemcacheRes *pRes, LDAPMessage *pMsg, 
+				    unsigned long size);
+static int memcache_free_from_list(LDAPMemCache *cache, ldapmemcacheRes *pRes, 
+				   int index);
+static int memcache_search(LDAP *ld, unsigned long key, LDAPMessage **ppRes);
+static int memcache_add(LDAP *ld, unsigned long key, int msgid,
+			const char *basedn);
+static int memcache_append(LDAP *ld, int msgid, LDAPMessage *pRes);
+static int memcache_append_last(LDAP *ld, int msgid, LDAPMessage *pRes);
+static int memcache_remove(LDAP *ld, int msgid);
+#if 0	/* function not used */
+static int memcache_remove_all(LDAP *ld);
+#endif /* 0 */
+static int memcache_access(LDAPMemCache *cache, int mode, 
+			   void *pData1, void *pData2, void *pData3);
+static void memcache_flush(LDAPMemCache *cache, char *dn, int scope,
+			   int flushresults);
+#ifdef LDAP_DEBUG
+static void memcache_print_list( LDAPMemCache *cache, int index );
+static void memcache_report_statistics( LDAPMemCache *cache );
+#endif /* LDAP_DEBUG */
+
+static int htable_calculate_size(int sizelimit);
+static int htable_sizeinbytes(HashTable *pTable);
+static int htable_put(HashTable *pTable, void *key, void *pData);
+static int htable_get(HashTable *pTable, void *key, void **ppData);
+static int htable_misc(HashTable *pTable, void *key, void *pData);
+static int htable_remove(HashTable *pTable, void *key, void **ppData);
+static int htable_removeall(HashTable *pTable, void *pData);
+static int htable_create(int size_limit, HashFuncPtr hashf,
+                         PutDataPtr putDataf, GetDataPtr getDataf,
+			 RemoveDataPtr removeDataf, ClrTableNodePtr clrNodef,
+			 MiscFuncPtr miscOpf, HashTable **ppTable);
+static int htable_free(HashTable *pTable);
+
+static int msgid_hashf(int table_size, void *key);
+static int msgid_putdata(void **ppTableData, void *key, void *pData);
+static int msgid_getdata(void *pTableData, void *key, void **ppData);
+static int msgid_removedata(void **ppTableData, void *key, void **ppData);
+static int msgid_clear_ld_items(void **ppTableData, void *key, void *pData);
+static void msgid_clearnode(void **ppTableData, void *pData);
+
+static int attrkey_hashf(int table_size, void *key);
+static int attrkey_putdata(void **ppTableData, void *key, void *pData);
+static int attrkey_getdata(void *pTableData, void *key, void **ppData);
+static int attrkey_removedata(void **ppTableData, void *key, void **ppData);
+static void attrkey_clearnode(void **ppTableData, void *pData);
+
+static unsigned long crc32_convert(char *buf, int len);
+
+/* Create a memcache object. */
+int
+LDAP_CALL
+ldap_memcache_init( unsigned long ttl, unsigned long size,
+                    char **baseDNs, struct ldap_thread_fns *thread_fns,
+		    LDAPMemCache **cachep )
+{
+    unsigned long total_size = 0;
+
+    LDAPDebug( LDAP_DEBUG_TRACE, "ldap_memcache_init\n", 0, 0, 0 );
+
+    if ( cachep == NULL ) {
+	return( LDAP_PARAM_ERROR );
+    }
+
+    if ((*cachep = (LDAPMemCache*)NSLDAPI_CALLOC(1,
+	    sizeof(LDAPMemCache))) == NULL) {
+	return ( LDAP_NO_MEMORY );
+    }
+
+    total_size += sizeof(LDAPMemCache);
+
+    (*cachep)->ldmemc_ttl = ttl;
+    (*cachep)->ldmemc_size = size;
+    (*cachep)->ldmemc_lds = NULL;
+
+    /* Non-zero default size needed for calculating size of hash tables */
+    size = (size ? size : MEMCACHE_DEF_SIZE);
+
+    if (thread_fns) {
+	memcpy(&((*cachep)->ldmemc_lock_fns), thread_fns, 
+           sizeof(struct ldap_thread_fns));
+    } else {
+	memset(&((*cachep)->ldmemc_lock_fns), 0, 
+	   sizeof(struct ldap_thread_fns));
+    }
+
+    (*cachep)->ldmemc_lock = LDAP_MEMCACHE_MUTEX_ALLOC( *cachep );
+
+    /* Cache basedns */
+    if (baseDNs != NULL) {
+
+	int i;
+
+	for (i = 0; baseDNs[i]; i++) {
+		;
+	}
+
+	(*cachep)->ldmemc_basedns = (char**)NSLDAPI_CALLOC(i + 1,
+		sizeof(char*));
+
+	if ((*cachep)->ldmemc_basedns == NULL) {
+    	    ldap_memcache_destroy(*cachep);
+	    *cachep = NULL;
+	    return ( LDAP_NO_MEMORY );
+	}
+
+	total_size += (i + 1) * sizeof(char*);
+
+	for (i = 0; baseDNs[i]; i++) {
+	    (*cachep)->ldmemc_basedns[i] = nsldapi_strdup(baseDNs[i]);
+	    total_size += strlen(baseDNs[i]) + 1;
+	}
+
+	(*cachep)->ldmemc_basedns[i] = NULL;
+    }
+
+    /* Create hash table for temporary cache */
+    if (htable_create(size, msgid_hashf, msgid_putdata, msgid_getdata,
+                      msgid_removedata, msgid_clearnode, msgid_clear_ld_items,
+		      &((*cachep)->ldmemc_resTmp)) != LDAP_SUCCESS) {
+	ldap_memcache_destroy(*cachep);
+	*cachep = NULL;
+	return( LDAP_NO_MEMORY );
+    }
+
+    total_size += htable_sizeinbytes((*cachep)->ldmemc_resTmp);
+
+    /* Create hash table for primary cache */
+    if (htable_create(size, attrkey_hashf, attrkey_putdata, 
+	              attrkey_getdata, attrkey_removedata, attrkey_clearnode,
+		      NULL, &((*cachep)->ldmemc_resLookup)) != LDAP_SUCCESS) {
+	ldap_memcache_destroy(*cachep);
+	*cachep = NULL;
+	return( LDAP_NO_MEMORY );
+    }
+
+    total_size += htable_sizeinbytes((*cachep)->ldmemc_resLookup);
+    
+    /* See if there is enough room so far */
+    if (memcache_adj_size(*cachep, total_size, MEMCACHE_SIZE_NON_ENTRIES,
+	                  MEMCACHE_SIZE_ADD) != LDAP_SUCCESS) {
+	ldap_memcache_destroy(*cachep);
+	*cachep = NULL;
+	return( LDAP_SIZELIMIT_EXCEEDED );
+    }
+
+    LDAPDebug( LDAP_DEBUG_TRACE, "ldap_memcache_init new cache 0x%p\n",
+	    *cachep, 0, 0 );
+
+    return( LDAP_SUCCESS );
+}
+
+/* Associates a ldap handle to a memcache object. */
+int
+LDAP_CALL
+ldap_memcache_set( LDAP *ld, LDAPMemCache *cache )
+{
+    int nRes = LDAP_SUCCESS;
+
+    LDAPDebug( LDAP_DEBUG_TRACE, "ldap_memcache_set\n", 0, 0, 0 );
+
+    if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) )
+	return( LDAP_PARAM_ERROR );
+
+    LDAP_MUTEX_LOCK( ld, LDAP_MEMCACHE_LOCK );
+
+    if (ld->ld_memcache != cache) {
+
+        LDAPMemCache *c = ld->ld_memcache;
+	ldapmemcacheld *pCur = NULL;
+	ldapmemcacheld *pPrev = NULL;
+
+	/* First dissociate handle from old cache */
+
+	LDAP_MEMCACHE_MUTEX_LOCK( c );
+
+	pCur = (c ? c->ldmemc_lds : NULL);
+	for (; pCur; pCur = pCur->ldmemcl_next) {
+	    if (pCur->ldmemcl_ld == ld)
+		break;
+	    pPrev = pCur;
+	}
+
+	if (pCur) {
+
+	    ldapmemcacheReqId reqid;
+
+	    reqid.ldmemcrid_ld = ld;
+	    reqid.ldmemcrid_msgid = -1;
+	    htable_misc(c->ldmemc_resTmp, (void*)&reqid, (void*)c);
+
+	    if (pPrev)
+		pPrev->ldmemcl_next = pCur->ldmemcl_next;
+	    else
+		c->ldmemc_lds = pCur->ldmemcl_next;
+	    NSLDAPI_FREE(pCur);
+	    pCur = NULL;
+
+	    memcache_adj_size(c, sizeof(ldapmemcacheld),
+	                MEMCACHE_SIZE_NON_ENTRIES, MEMCACHE_SIZE_DEDUCT);
+	}
+
+	LDAP_MEMCACHE_MUTEX_UNLOCK( c );
+
+	ld->ld_memcache = NULL;
+
+	/* Exit if no new cache is specified */
+	if (cache == NULL) {
+	    LDAP_MUTEX_UNLOCK( ld, LDAP_MEMCACHE_LOCK );
+	    return( LDAP_SUCCESS );
+	}
+
+	/* Then associate handle with new cache */
+
+        LDAP_MEMCACHE_MUTEX_LOCK( cache );
+
+	if ((nRes = memcache_adj_size(cache, sizeof(ldapmemcacheld),
+	       MEMCACHE_SIZE_NON_ENTRIES, MEMCACHE_SIZE_ADD)) != LDAP_SUCCESS) {
+	    LDAP_MEMCACHE_MUTEX_UNLOCK( cache );
+	    LDAP_MUTEX_UNLOCK( ld, LDAP_MEMCACHE_LOCK );
+	    return nRes;
+	}
+
+	pCur = (ldapmemcacheld*)NSLDAPI_CALLOC(1, sizeof(ldapmemcacheld));
+	if (pCur == NULL) {
+	    memcache_adj_size(cache, sizeof(ldapmemcacheld), 
+		              MEMCACHE_SIZE_NON_ENTRIES, MEMCACHE_SIZE_DEDUCT);
+	    nRes = LDAP_NO_MEMORY;
+	} else {
+	    pCur->ldmemcl_ld = ld;
+	    pCur->ldmemcl_next = cache->ldmemc_lds;
+	    cache->ldmemc_lds = pCur;
+	    ld->ld_memcache = cache;
+	}
+
+	LDAP_MEMCACHE_MUTEX_UNLOCK( cache );
+    }
+
+    LDAP_MUTEX_UNLOCK( ld, LDAP_MEMCACHE_LOCK );
+
+    return nRes;
+}
+
+/* Retrieves memcache with which the ldap handle has been associated. */
+int
+LDAP_CALL
+ldap_memcache_get( LDAP *ld, LDAPMemCache **cachep )
+{
+    LDAPDebug( LDAP_DEBUG_TRACE, "ldap_memcache_get ld: 0x%p\n", ld, 0, 0 );
+
+    if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) || cachep == NULL ) { 
+	return( LDAP_PARAM_ERROR );
+    }
+
+    LDAP_MUTEX_LOCK( ld, LDAP_MEMCACHE_LOCK );
+    *cachep = ld->ld_memcache;
+    LDAP_MUTEX_UNLOCK( ld, LDAP_MEMCACHE_LOCK );
+
+    return( LDAP_SUCCESS );
+}
+
+/*
+ * Function that stays inside libldap and proactively expires items from
+ * the given cache.  This should be called from a newly created thread since
+ * it will not return until after ldap_memcache_destroy() is called.
+ */
+void
+LDAP_CALL
+ldap_memcache_update( LDAPMemCache *cache )
+{
+    LDAPDebug( LDAP_DEBUG_TRACE, "ldap_memcache_update: cache 0x%p\n",
+	    cache, 0, 0 );
+
+    if ( !NSLDAPI_VALID_MEMCACHE_POINTER( cache )) {
+	return;
+    }
+
+    LDAP_MEMCACHE_MUTEX_LOCK( cache );
+    memcache_access(cache, MEMCACHE_ACCESS_UPDATE, NULL, NULL, NULL);
+    LDAP_MEMCACHE_MUTEX_UNLOCK( cache );
+}
+
+/* Removes specified entries from given memcache. Only clears out search
+   results that included search entries. */
+void
+LDAP_CALL
+ldap_memcache_flush( LDAPMemCache *cache, char *dn, int scope )
+{
+    LDAPDebug( LDAP_DEBUG_TRACE,
+        "ldap_memcache_flush( cache: 0x%p, dn: %s, scope: %d)\n",
+        cache, ( dn == NULL ) ? "(null)" : dn, scope );
+    memcache_flush(cache, dn, scope, 0 /* Don't use result flush mode */);
+}
+
+/* Removes specified entries from given memcache, including search
+   results that returned no entries. */
+void
+LDAP_CALL
+ldap_memcache_flush_results( LDAPMemCache *cache, char *dn, int scope )
+{
+    LDAPDebug( LDAP_DEBUG_TRACE,
+        "ldap_memcache_flush_results( cache: 0x%p, dn: %s, scope: %d)\n",
+        cache, ( dn == NULL ) ? "(null)" : dn, scope );
+    memcache_flush(cache, dn, scope, 1 /* Use result flush mode */);
+}
+
+/* Destroys the given memcache. */
+void
+LDAP_CALL
+ldap_memcache_destroy( LDAPMemCache *cache )
+{
+    int i = 0;
+    unsigned long size = sizeof(LDAPMemCache);
+    ldapmemcacheld *pNode = NULL, *pNextNode = NULL;
+
+    LDAPDebug( LDAP_DEBUG_TRACE, "ldap_memcache_destroy( 0x%p )\n",
+	    cache, 0, 0 );
+
+    if ( !NSLDAPI_VALID_MEMCACHE_POINTER( cache )) {
+	return;
+    }
+
+    /* Dissociate all ldap handes from this cache. */
+    LDAP_MEMCACHE_MUTEX_LOCK( cache );
+
+    for (pNode = cache->ldmemc_lds; pNode; pNode = pNextNode, i++) {
+        LDAP_MUTEX_LOCK( pNode->ldmemcl_ld, LDAP_MEMCACHE_LOCK );
+	cache->ldmemc_lds = pNode->ldmemcl_next;
+	pNode->ldmemcl_ld->ld_memcache = NULL;
+        LDAP_MUTEX_UNLOCK( pNode->ldmemcl_ld, LDAP_MEMCACHE_LOCK );
+	pNextNode = pNode->ldmemcl_next;
+	NSLDAPI_FREE(pNode);
+    }
+
+    size += i * sizeof(ldapmemcacheld);
+
+    LDAP_MEMCACHE_MUTEX_UNLOCK( cache );
+
+    /* Free array of basedns */
+    if (cache->ldmemc_basedns) {
+	for (i = 0; cache->ldmemc_basedns[i]; i++) {
+	    size += strlen(cache->ldmemc_basedns[i]) + 1;
+	    NSLDAPI_FREE(cache->ldmemc_basedns[i]);
+	}
+	size += (i + 1) * sizeof(char*);
+	NSLDAPI_FREE(cache->ldmemc_basedns);
+    }
+
+    /* Free hash table used for temporary cache */
+    if (cache->ldmemc_resTmp) {
+	size += htable_sizeinbytes(cache->ldmemc_resTmp);
+	memcache_access(cache, MEMCACHE_ACCESS_DELETE_ALL, NULL, NULL, NULL);
+	htable_free(cache->ldmemc_resTmp);
+    }
+
+    /* Free hash table used for primary cache */
+    if (cache->ldmemc_resLookup) {
+	size += htable_sizeinbytes(cache->ldmemc_resLookup);
+	memcache_access(cache, MEMCACHE_ACCESS_FLUSH_ALL, NULL, NULL, NULL);
+	htable_free(cache->ldmemc_resLookup);
+    }
+
+    memcache_adj_size(cache, size, MEMCACHE_SIZE_NON_ENTRIES, 
+	              MEMCACHE_SIZE_DEDUCT);
+
+    LDAP_MEMCACHE_MUTEX_FREE( cache );
+
+    NSLDAPI_FREE(cache);
+}
+
+/************************* Internal API Functions ****************************/
+
+/* Creates an integer key by applying the Cyclic Reduntency Check algorithm on
+   a long string formed by concatenating all the search parameters plus the
+   current bind DN.  The key is used in the cache for looking up cached
+   entries.  It is assumed that the CRC algorithm will generate
+   different integers from different byte strings. */
+int
+ldap_memcache_createkey(LDAP *ld, const char *base, int scope, 
+			const char *filter, char **attrs, 
+                        int attrsonly, LDAPControl **serverctrls, 
+                        LDAPControl **clientctrls, unsigned long *keyp)
+{
+    int nRes, i, j, i_smallest;
+    int len;
+    int defport;
+    char buf[50];
+    char *tmp, *defhost, *binddn, *keystr, *tmpbase;
+
+    if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) || (keyp == NULL) )
+	return( LDAP_PARAM_ERROR );
+
+    *keyp = 0;
+
+    if (!memcache_exist(ld))
+	return( LDAP_LOCAL_ERROR );
+
+    LDAP_MUTEX_LOCK( ld, LDAP_MEMCACHE_LOCK );
+    LDAP_MEMCACHE_MUTEX_LOCK( ld->ld_memcache );
+    nRes = memcache_validate_basedn(ld->ld_memcache, base);
+    LDAP_MEMCACHE_MUTEX_UNLOCK( ld->ld_memcache );
+    LDAP_MUTEX_UNLOCK( ld, LDAP_MEMCACHE_LOCK );
+
+    if (nRes != LDAP_SUCCESS)
+	return nRes;
+
+    defhost = NSLDAPI_STR_NONNULL(ld->ld_defhost);
+    defport = ld->ld_defport;
+    tmpbase = nsldapi_strdup(NSLDAPI_STR_NONNULL(base));
+    memcache_trim_basedn_spaces(tmpbase);
+
+    if ((binddn = nsldapi_get_binddn(ld)) == NULL)
+	binddn = "";
+
+    sprintf(buf, "%i\n%i\n%i\n", defport, scope, (attrsonly ? 1 : 0));
+    len = NSLDAPI_SAFE_STRLEN(buf) + NSLDAPI_SAFE_STRLEN(tmpbase) +
+	  NSLDAPI_SAFE_STRLEN(filter) + NSLDAPI_SAFE_STRLEN(defhost) +
+	  NSLDAPI_SAFE_STRLEN(binddn);
+
+    if (attrs) {
+	for (i = 0; attrs[i]; i++) {
+
+	    for (i_smallest = j = i; attrs[j]; j++) {
+		if (strcasecmp(attrs[i_smallest], attrs[j]) > 0)
+		    i_smallest = j;
+	    }
+
+	    if (i != i_smallest) {
+		tmp = attrs[i];
+		attrs[i] = attrs[i_smallest];
+		attrs[i_smallest] = tmp;
+	    }
+
+	    len += NSLDAPI_SAFE_STRLEN(attrs[i]);
+	}
+    } else {
+	len += 1;
+    }
+
+    len += memcache_get_ctrls_len(serverctrls) + 
+	   memcache_get_ctrls_len(clientctrls) + 1;
+
+    if ((keystr = (char*)NSLDAPI_CALLOC(len, sizeof(char))) == NULL) {
+	NSLDAPI_FREE(defhost);
+	return( LDAP_NO_MEMORY );
+    }
+
+    sprintf(keystr, "%s\n%s\n%s\n%s\n%s\n", binddn, tmpbase,
+	    NSLDAPI_STR_NONNULL(defhost), NSLDAPI_STR_NONNULL(filter), 
+	    NSLDAPI_STR_NONNULL(buf));
+
+    if (attrs) {
+	for (i = 0; attrs[i]; i++) {
+	    strcat(keystr, NSLDAPI_STR_NONNULL(attrs[i]));
+	    strcat(keystr, "\n");
+	}
+    } else {
+	strcat(keystr, "\n");
+    }
+
+    for (tmp = keystr; *tmp; 
+         *tmp += (*tmp >= 'a' && *tmp <= 'z' ? 'A'-'a' : 0), tmp++) {
+		;
+	}
+
+    memcache_append_ctrls(keystr, serverctrls, clientctrls);
+
+    /* CRC algorithm */
+    *keyp = crc32_convert(keystr, len);
+
+    NSLDAPI_FREE(keystr);
+    NSLDAPI_FREE(tmpbase);
+
+    return LDAP_SUCCESS;
+}
+
+/* Searches the cache for the right cached entries, and if found, attaches
+   them to the given ldap handle.  This function relies on locking by the
+   caller. */
+int
+ldap_memcache_result(LDAP *ld, int msgid, unsigned long key)
+{
+    int nRes;
+    LDAPMessage *pMsg = NULL;
+
+    LDAPDebug( LDAP_DEBUG_TRACE,
+	    "ldap_memcache_result( ld: 0x%p, msgid: %d, key: 0x%8.8lx)\n",
+	    ld, msgid, key );
+
+    if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) || (msgid < 0) ) {
+	return( LDAP_PARAM_ERROR );
+    }
+
+    if (!memcache_exist(ld)) {
+	return( LDAP_LOCAL_ERROR );
+    }
+
+    LDAP_MUTEX_LOCK( ld, LDAP_MEMCACHE_LOCK );
+    LDAP_MEMCACHE_MUTEX_LOCK( ld->ld_memcache );
+
+    /* Search the cache and append the results to ld if found */
+    ++ld->ld_memcache->ldmemc_stats.ldmemcstat_tries;
+    if ((nRes = memcache_search(ld, key, &pMsg)) == LDAP_SUCCESS) {
+	nRes = memcache_add_to_ld(ld, msgid, pMsg);
+	++ld->ld_memcache->ldmemc_stats.ldmemcstat_hits;
+	LDAPDebug( LDAP_DEBUG_TRACE,
+		"ldap_memcache_result: key 0x%8.8lx found in cache\n",
+		key, 0, 0 );
+    } else {
+	LDAPDebug( LDAP_DEBUG_TRACE,
+		"ldap_memcache_result: key 0x%8.8lx not found in cache\n",
+		key, 0, 0 );
+    }
+
+#ifdef LDAP_DEBUG
+    memcache_print_list( ld->ld_memcache, LIST_LRU );
+    memcache_report_statistics( ld->ld_memcache );
+#endif /* LDAP_DEBUG */
+
+    LDAP_MEMCACHE_MUTEX_UNLOCK( ld->ld_memcache );
+    LDAP_MUTEX_UNLOCK( ld, LDAP_MEMCACHE_LOCK );
+
+    return nRes;
+}
+
+/* Creates a new header in the cache so that entries arriving from the
+   directory server can later be cached under the header. */
+int
+ldap_memcache_new(LDAP *ld, int msgid, unsigned long key, const char *basedn)
+{
+    int nRes;
+
+    if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) ) {
+	return( LDAP_PARAM_ERROR );
+    }
+
+    LDAP_MUTEX_LOCK( ld, LDAP_MEMCACHE_LOCK );
+
+    if (!memcache_exist(ld)) {
+        LDAP_MUTEX_UNLOCK( ld, LDAP_MEMCACHE_LOCK );
+	return( LDAP_LOCAL_ERROR );
+    }
+
+    LDAP_MEMCACHE_MUTEX_LOCK( ld->ld_memcache );
+    nRes = memcache_add(ld, key, msgid, basedn);
+    LDAP_MEMCACHE_MUTEX_UNLOCK( ld->ld_memcache );
+    LDAP_MUTEX_UNLOCK( ld, LDAP_MEMCACHE_LOCK );
+
+    return nRes;
+}
+
+/* Appends a chain of entries to an existing cache header.  Parameter "bLast"
+   indicates whether there will be more entries arriving for the search in
+   question. */
+int
+ldap_memcache_append(LDAP *ld, int msgid, int bLast, LDAPMessage *result)
+{
+    int nRes = LDAP_SUCCESS;
+
+    LDAPDebug( LDAP_DEBUG_TRACE, "ldap_memcache_append( ld: 0x%p, ", ld, 0, 0 );
+    LDAPDebug( LDAP_DEBUG_TRACE, "msgid %d, bLast: %d, result: 0x%p)\n",
+	    msgid, bLast, result );
+
+    if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) || !result ) {
+	return( LDAP_PARAM_ERROR );
+    }
+
+    LDAP_MUTEX_LOCK( ld, LDAP_MEMCACHE_LOCK );
+
+    if (!memcache_exist(ld)) {
+        LDAP_MUTEX_UNLOCK( ld, LDAP_MEMCACHE_LOCK );
+	return( LDAP_LOCAL_ERROR );
+    }
+
+    LDAP_MEMCACHE_MUTEX_LOCK( ld->ld_memcache );
+
+    if (!bLast)
+	nRes = memcache_append(ld, msgid, result);
+    else
+	nRes = memcache_append_last(ld, msgid, result);
+
+    LDAPDebug( LDAP_DEBUG_TRACE,
+	    "ldap_memcache_append: %s result for msgid %d\n",
+	    ( nRes == LDAP_SUCCESS ) ? "added" : "failed to add", msgid , 0 );
+
+    LDAP_MEMCACHE_MUTEX_UNLOCK( ld->ld_memcache );
+    LDAP_MUTEX_UNLOCK( ld, LDAP_MEMCACHE_LOCK );
+
+    return nRes;
+}
+
+/* Removes partially cached results for a search as a result of calling
+   ldap_abandon() by the client. */
+int
+ldap_memcache_abandon(LDAP *ld, int msgid)
+{
+    int nRes;
+
+    if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) || (msgid < 0) ) {
+	return( LDAP_PARAM_ERROR );
+    }
+
+    LDAP_MUTEX_LOCK( ld, LDAP_MEMCACHE_LOCK );
+
+    if (!memcache_exist(ld)) {
+        LDAP_MUTEX_UNLOCK( ld, LDAP_MEMCACHE_LOCK );
+	return( LDAP_LOCAL_ERROR );
+    }
+
+    LDAP_MEMCACHE_MUTEX_LOCK( ld->ld_memcache );
+    nRes = memcache_remove(ld, msgid);
+    LDAP_MEMCACHE_MUTEX_UNLOCK( ld->ld_memcache );
+    LDAP_MUTEX_UNLOCK( ld, LDAP_MEMCACHE_LOCK );
+
+    return nRes;
+}
+
+/*************************** helper functions *******************************/
+
+/* Removes extraneous spaces in a basedn so that basedns differ by only those
+   spaces will be treated as equal.  Extraneous spaces are those that
+   precedes the basedn and those that follow a comma. */
+/*
+ * XXXmcs: this is a bit too agressive... we need to deal with the fact that
+ * commas and spaces may be quoted, in which case it is wrong to remove them.
+ */
+static void
+memcache_trim_basedn_spaces(char *basedn)
+{
+    char *pRead, *pWrite;
+
+    if (!basedn) 
+	return;
+
+    for (pWrite = pRead = basedn; *pRead; ) {
+	for (; *pRead && NSLDAPI_IS_SPACE(*pRead); pRead++) {
+		;
+	}
+	for (; *pRead && !NSLDAPI_IS_SEPARATER(*pRead);
+	    *(pWrite++) = *(pRead++)) {
+	    ;
+	}
+	*(pWrite++) = (*pRead ? *(pRead++) : *pRead);
+    }
+}
+
+/* Verifies whether the results of a search should be cached or not by
+   checking if the search's basedn falls under any of the basedns for which
+   the memcache is responsible. */
+static int
+memcache_validate_basedn(LDAPMemCache *cache, const char *basedn)
+{
+    int i;
+
+    if ( cache->ldmemc_basedns == NULL ) {
+	return( LDAP_SUCCESS );
+    }
+
+#if 1
+    if (basedn == NULL) {
+	basedn = "";
+    }
+#else
+    /* XXXmcs: I do not understand this code... */
+    if (basedn == NULL)
+	return (cache->ldmemc_basedns && cache->ldmemc_basedns[0] ?
+	                             LDAP_OPERATIONS_ERROR : LDAP_SUCCESS);
+    }
+#endif
+
+    for (i = 0; cache->ldmemc_basedns[i]; i++) {
+	if (memcache_compare_dn(basedn, cache->ldmemc_basedns[i], 
+	                        LDAP_SCOPE_SUBTREE) == LDAP_COMPARE_TRUE) {
+	    return( LDAP_SUCCESS );
+	}
+    }
+
+    return( LDAP_OPERATIONS_ERROR );
+}
+
+/* Calculates the length of the buffer needed to concatenate the contents of
+   a ldap control. */
+static int
+memcache_get_ctrls_len(LDAPControl **ctrls)
+{
+    int len = 0, i;
+
+    if (ctrls) {
+	for (i = 0; ctrls[i]; i++) {
+	    len += strlen(NSLDAPI_STR_NONNULL(ctrls[i]->ldctl_oid)) +
+	           (ctrls[i]->ldctl_value).bv_len + 4;
+	}
+    }
+
+    return len;
+}
+
+/* Contenates the contents of client and server controls to a buffer. */
+static void
+memcache_append_ctrls(char *buf, LDAPControl **serverCtrls,
+				  LDAPControl **clientCtrls)
+{
+    int i, j;
+    char *pCh = buf + strlen(buf);
+    LDAPControl **ctrls;
+
+    for (j = 0; j < 2; j++) {
+
+	if ((ctrls = (j ? clientCtrls : serverCtrls)) == NULL)
+	    continue;
+
+	for (i = 0; ctrls[i]; i++) {
+	    sprintf(pCh, "%s\n", NSLDAPI_STR_NONNULL(ctrls[i]->ldctl_oid));
+	    pCh += strlen(NSLDAPI_STR_NONNULL(ctrls[i]->ldctl_oid)) + 1;
+	    if ((ctrls[i]->ldctl_value).bv_len > 0) {
+		memcpy(pCh, (ctrls[i]->ldctl_value).bv_val, 
+		       (ctrls[i]->ldctl_value).bv_len);
+		pCh += (ctrls[i]->ldctl_value).bv_len;
+	    }
+	    sprintf(pCh, "\n%i\n", (ctrls[i]->ldctl_iscritical ? 1 : 0));
+	    pCh += 3;
+	}
+    }
+}
+
+/* Increases or decreases the size (in bytes) the given memcache currently
+   uses.  If the size goes over the limit, the function returns an error. */
+static int
+memcache_adj_size(LDAPMemCache *cache, unsigned long size,
+                  int usageFlags, int bAdd)
+{
+    LDAPDebug( LDAP_DEBUG_TRACE,
+	    "memcache_adj_size: attempting to %s %ld %s bytes...\n",
+	    bAdd ? "add" : "remove", size,
+	    ( usageFlags & MEMCACHE_SIZE_ENTRIES ) ? "entry" : "non-entry" );
+
+    if (bAdd) {
+	cache->ldmemc_size_used += size;
+	if ((cache->ldmemc_size > 0) &&
+	    (cache->ldmemc_size_used > cache->ldmemc_size)) {
+
+	    if (size > cache->ldmemc_size_entries) {
+	        cache->ldmemc_size_used -= size;
+		LDAPDebug( LDAP_DEBUG_TRACE,
+			"memcache_adj_size: failed (size > size_entries %ld).\n",
+			cache->ldmemc_size_entries, 0, 0 );
+		return( LDAP_SIZELIMIT_EXCEEDED );
+	    }
+
+	    while (cache->ldmemc_size_used > cache->ldmemc_size) {
+		if (memcache_access(cache, MEMCACHE_ACCESS_FLUSH_LRU,
+		                    NULL, NULL, NULL) != LDAP_SUCCESS) {
+	            cache->ldmemc_size_used -= size;
+		    LDAPDebug( LDAP_DEBUG_TRACE,
+			    "memcache_adj_size: failed (LRU flush failed).\n",
+			    0, 0, 0 );
+		    return( LDAP_SIZELIMIT_EXCEEDED );
+	        }
+	    }
+	}
+	if (usageFlags & MEMCACHE_SIZE_ENTRIES)
+	    cache->ldmemc_size_entries += size;
+    } else {
+	cache->ldmemc_size_used -= size;
+	assert(cache->ldmemc_size_used >= 0);
+	if (usageFlags & MEMCACHE_SIZE_ENTRIES)
+	    cache->ldmemc_size_entries -= size;
+    }
+
+#ifdef LDAP_DEBUG
+    if ( cache->ldmemc_size == 0 ) {	/* no size limit */
+	LDAPDebug( LDAP_DEBUG_TRACE,
+		"memcache_adj_size: succeeded (new size: %ld bytes).\n",
+		cache->ldmemc_size_used, 0, 0 );
+    } else {
+	LDAPDebug( LDAP_DEBUG_TRACE,
+		"memcache_adj_size: succeeded (new size: %ld bytes, "
+		"free space: %ld bytes).\n", cache->ldmemc_size_used,
+		cache->ldmemc_size - cache->ldmemc_size_used, 0 );
+    }
+#endif /* LDAP_DEBUG */
+
+    return( LDAP_SUCCESS );
+}
+
+/* Searches the cache for results for a particular search identified by
+   parameter "key", which was generated ldap_memcache_createkey(). */
+static int
+memcache_search(LDAP *ld, unsigned long key, LDAPMessage **ppRes)
+{
+    int nRes;
+    ldapmemcacheRes *pRes;
+
+    *ppRes = NULL;
+
+    if (!memcache_exist(ld))
+        return LDAP_LOCAL_ERROR;
+
+    nRes = memcache_access(ld->ld_memcache, MEMCACHE_ACCESS_FIND,
+	                   (void*)&key, (void*)(&pRes), NULL);
+
+    if (nRes != LDAP_SUCCESS)
+	return nRes;
+
+    *ppRes = pRes->ldmemcr_resHead;
+    assert((pRes->ldmemcr_req_id).ldmemcrid_msgid == -1);
+
+    return( LDAP_SUCCESS );
+}
+
+/* Adds a new header into the cache as a place holder for entries
+   arriving later. */
+static int
+memcache_add(LDAP *ld, unsigned long key, int msgid,
+			const char *basedn)
+{
+    ldapmemcacheReqId reqid;
+
+    if (!memcache_exist(ld))
+        return LDAP_LOCAL_ERROR;
+
+    reqid.ldmemcrid_msgid = msgid;
+    reqid.ldmemcrid_ld = ld;
+
+    return memcache_access(ld->ld_memcache, MEMCACHE_ACCESS_ADD,
+	                   (void*)&key, (void*)&reqid, (void*)basedn);
+}
+
+/* Appends search entries arriving from the dir server to the cache. */
+static int
+memcache_append(LDAP *ld, int msgid, LDAPMessage *pRes)
+{
+    ldapmemcacheReqId reqid;
+
+    if (!memcache_exist(ld))
+        return LDAP_LOCAL_ERROR;
+
+    reqid.ldmemcrid_msgid = msgid;
+    reqid.ldmemcrid_ld = ld;
+
+    return memcache_access(ld->ld_memcache, MEMCACHE_ACCESS_APPEND,
+	                   (void*)&reqid, (void*)pRes, NULL);
+}
+
+/* Same as memcache_append(), but the entries being appended are the
+   last from the dir server.  Once all entries for a search have arrived,
+   the entries are moved from secondary to primary cache, and a time
+   stamp is given to the entries. */
+static int
+memcache_append_last(LDAP *ld, int msgid, LDAPMessage *pRes)
+{
+    ldapmemcacheReqId reqid;
+
+    if (!memcache_exist(ld))
+        return LDAP_LOCAL_ERROR;
+
+    reqid.ldmemcrid_msgid = msgid;
+    reqid.ldmemcrid_ld = ld;
+
+    return memcache_access(ld->ld_memcache, MEMCACHE_ACCESS_APPEND_LAST,
+	                   (void*)&reqid, (void*)pRes, NULL);
+}
+
+/* Removes entries from the temporary cache. */
+static int
+memcache_remove(LDAP *ld, int msgid)
+{
+    ldapmemcacheReqId reqid;
+
+    if (!memcache_exist(ld))
+        return LDAP_LOCAL_ERROR;
+
+    reqid.ldmemcrid_msgid = msgid;
+    reqid.ldmemcrid_ld = ld;
+
+    return memcache_access(ld->ld_memcache, MEMCACHE_ACCESS_DELETE,
+	                   (void*)&reqid, NULL, NULL);
+}
+
+#if 0 /* this function is not used */
+/* Wipes out everything in the temporary cache directory. */
+static int
+memcache_remove_all(LDAP *ld)
+{
+    if (!memcache_exist(ld))
+        return LDAP_LOCAL_ERROR;
+
+    return memcache_access(ld->ld_memcache, MEMCACHE_ACCESS_DELETE_ALL,
+	                   NULL, NULL, NULL);
+}
+#endif /* 0 */
+
+/* Returns TRUE or FALSE */
+static int
+memcache_exist(LDAP *ld)
+{
+    return (ld->ld_memcache != NULL);
+}
+
+/* Attaches cached entries to an ldap handle. */
+static int
+memcache_add_to_ld(LDAP *ld, int msgid, LDAPMessage *pMsg)
+{
+    int nRes = LDAP_SUCCESS;
+    LDAPMessage **r;
+    LDAPMessage *pCopy;
+
+    nRes = memcache_dup_message(pMsg, msgid, 1, &pCopy, NULL);
+    if (nRes != LDAP_SUCCESS)
+	return nRes;
+
+    LDAP_MUTEX_LOCK( ld, LDAP_RESP_LOCK );
+
+    for (r = &(ld->ld_responses); *r; r = &((*r)->lm_next))
+	if ((*r)->lm_msgid == msgid)
+	    break;
+
+    if (*r)
+	for (r = &((*r)->lm_chain); *r; r = &((*r)->lm_chain)) {
+		;
+	}
+
+    *r = pCopy;
+
+    LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
+    
+    return nRes;
+}
+
+/* Check if main_dn is included in {dn, scope} */
+static int
+memcache_compare_dn(const char *main_dn, const char *dn, int scope)
+{
+    int nRes;
+    char **components = NULL;
+    char **main_components = NULL;
+
+    components = ldap_explode_dn(dn, 0);
+    main_components = ldap_explode_dn(main_dn, 0);
+
+    if (!components || !main_components) {
+	nRes = LDAP_COMPARE_TRUE;
+    }
+    else {
+
+	int i, main_i;
+
+	main_i = ldap_count_values(main_components) - 1;
+	i = ldap_count_values(components) - 1;
+
+	for (; i >= 0 && main_i >= 0; i--, main_i--) {
+	    if (strcasecmp(main_components[main_i], components[i]))
+		break;
+	}
+
+	if (i >= 0 && main_i >= 0) {
+	    nRes = LDAP_COMPARE_FALSE;
+	}
+	else if (i < 0 && main_i < 0) {
+	    if (scope != LDAP_SCOPE_ONELEVEL)
+		nRes = LDAP_COMPARE_TRUE;
+	    else
+		nRes = LDAP_COMPARE_FALSE;
+	}
+	else if (main_i < 0) {
+	    nRes = LDAP_COMPARE_FALSE;
+	}
+	else {
+	    if (scope == LDAP_SCOPE_BASE) 
+		nRes = LDAP_COMPARE_FALSE;
+	    else if (scope == LDAP_SCOPE_SUBTREE)
+		nRes = LDAP_COMPARE_TRUE;
+	    else if (main_i == 0)
+		nRes = LDAP_COMPARE_TRUE;
+	    else
+		nRes = LDAP_COMPARE_FALSE;
+	}
+    }
+
+    if (components)
+	ldap_value_free(components);
+
+    if (main_components)
+	ldap_value_free(main_components);
+
+    return nRes;
+}
+
+/* Dup a complete separate copy of a berelement, including the buffers
+   the berelement points to. */
+static BerElement*
+memcache_ber_dup(BerElement* pBer, unsigned long *pSize)
+{
+    BerElement *p = ber_dup(pBer);
+
+    *pSize = 0;
+
+    if (p) {
+
+	*pSize += sizeof(BerElement) + EXTRA_SIZE;
+
+	if (p->ber_len <= EXTRA_SIZE) {
+	    p->ber_flags |= LBER_FLAG_NO_FREE_BUFFER;
+	    p->ber_buf = (char*)p + sizeof(BerElement);
+	} else {
+	    p->ber_flags &= ~LBER_FLAG_NO_FREE_BUFFER;
+	    p->ber_buf = (char*)NSLDAPI_CALLOC(1, p->ber_len);
+	    *pSize += (p->ber_buf ? p->ber_len : 0);
+	}
+
+	if (p->ber_buf) {
+	    p->ber_ptr = p->ber_buf + (pBer->ber_ptr - pBer->ber_buf);
+	    p->ber_end = p->ber_buf + p->ber_len;
+	    memcpy(p->ber_buf, pBer->ber_buf, p->ber_len);
+	} else {
+	    ber_free(p, 0);
+	    p = NULL;
+	    *pSize = 0;
+	}
+    }
+
+    return p;
+}
+
+/* Dup a entry or a chain of entries. */
+static int
+memcache_dup_message(LDAPMessage *res, int msgid, int fromcache,
+				LDAPMessage **ppResCopy, unsigned long *pSize)
+{
+    int nRes = LDAP_SUCCESS;
+    unsigned long ber_size;
+    LDAPMessage *pCur;
+    LDAPMessage **ppCurNew;
+
+    *ppResCopy = NULL;
+
+    if (pSize)
+	*pSize = 0;
+
+    /* Make a copy of res */
+    for (pCur = res, ppCurNew = ppResCopy; pCur; 
+         pCur = pCur->lm_chain, ppCurNew = &((*ppCurNew)->lm_chain)) {
+
+	if ((*ppCurNew = (LDAPMessage*)NSLDAPI_CALLOC(1, 
+	                                     sizeof(LDAPMessage))) == NULL) {
+	    nRes = LDAP_NO_MEMORY;
+	    break;
+	}
+
+	memcpy(*ppCurNew, pCur, sizeof(LDAPMessage));
+	(*ppCurNew)->lm_next = NULL;
+	(*ppCurNew)->lm_ber = memcache_ber_dup(pCur->lm_ber, &ber_size);
+	(*ppCurNew)->lm_msgid = msgid;
+	(*ppCurNew)->lm_fromcache = (fromcache != 0);
+
+	if (pSize)
+	    *pSize += sizeof(LDAPMessage) + ber_size;
+    }
+
+    if ((nRes != LDAP_SUCCESS) && (*ppResCopy != NULL)) {
+	ldap_msgfree(*ppResCopy);
+	*ppResCopy = NULL;
+	if (pSize)
+	    *pSize = 0;
+    }
+
+    return nRes;
+}
+
+/************************* Cache Functions ***********************/
+
+/* Frees a cache header. */
+static int
+memcache_free_entry(LDAPMemCache *cache, ldapmemcacheRes *pRes)
+{
+    if (pRes) {
+
+	unsigned long size = sizeof(ldapmemcacheRes); 
+
+	if (pRes->ldmemcr_basedn) {
+	    size += strlen(pRes->ldmemcr_basedn) + 1;
+	    NSLDAPI_FREE(pRes->ldmemcr_basedn);
+	}
+
+	if (pRes->ldmemcr_resHead) {
+	    size += pRes->ldmemcr_resSize;
+	    ldap_msgfree(pRes->ldmemcr_resHead);
+	}
+
+	NSLDAPI_FREE(pRes);
+
+	memcache_adj_size(cache, size, MEMCACHE_SIZE_ENTRIES,
+	                  MEMCACHE_SIZE_DEDUCT);
+    }
+
+    return( LDAP_SUCCESS );
+}
+
+/* Detaches a cache header from the list of headers. */
+static int
+memcache_free_from_list(LDAPMemCache *cache, ldapmemcacheRes *pRes, int index)
+{
+    if (pRes->ldmemcr_prev[index])
+	pRes->ldmemcr_prev[index]->ldmemcr_next[index] = 
+	                                     pRes->ldmemcr_next[index];
+
+    if (pRes->ldmemcr_next[index])
+	pRes->ldmemcr_next[index]->ldmemcr_prev[index] = 
+	                                     pRes->ldmemcr_prev[index];
+
+    if (cache->ldmemc_resHead[index] == pRes)
+	cache->ldmemc_resHead[index] = pRes->ldmemcr_next[index];
+
+    if (cache->ldmemc_resTail[index] == pRes)
+	cache->ldmemc_resTail[index] = pRes->ldmemcr_prev[index];
+
+    pRes->ldmemcr_prev[index] = NULL;
+    pRes->ldmemcr_next[index] = NULL;
+
+    return( LDAP_SUCCESS );
+}
+
+/* Inserts a new cache header to a list of headers. */
+static int
+memcache_add_to_list(LDAPMemCache *cache, ldapmemcacheRes *pRes, int index)
+{
+    if (cache->ldmemc_resHead[index])
+	cache->ldmemc_resHead[index]->ldmemcr_prev[index] = pRes;
+    else
+	cache->ldmemc_resTail[index] = pRes;
+
+    pRes->ldmemcr_prev[index] = NULL;
+    pRes->ldmemcr_next[index] = cache->ldmemc_resHead[index];
+    cache->ldmemc_resHead[index] = pRes;
+
+    return( LDAP_SUCCESS );
+}
+
+/* Appends a chain of entries to the given cache header. */
+static int
+memcache_add_res_to_list(ldapmemcacheRes *pRes, LDAPMessage *pMsg,
+				    unsigned long size)
+{
+    if (pRes->ldmemcr_resTail)
+	pRes->ldmemcr_resTail->lm_chain = pMsg;
+    else
+	pRes->ldmemcr_resHead = pMsg;
+
+    for (pRes->ldmemcr_resTail = pMsg;
+         pRes->ldmemcr_resTail->lm_chain;
+         pRes->ldmemcr_resTail = pRes->ldmemcr_resTail->lm_chain) {
+		;
+	}
+
+    pRes->ldmemcr_resSize += size;
+
+    return( LDAP_SUCCESS );
+}
+
+
+#ifdef LDAP_DEBUG
+static void
+memcache_print_list( LDAPMemCache *cache, int index )
+{
+    char		*name;
+    ldapmemcacheRes	*restmp;
+
+    switch( index ) {
+    case LIST_TTL:
+	name = "TTL";
+	break;
+    case LIST_LRU:
+	name = "LRU";
+	break;
+    case LIST_TMP:
+	name = "TMP";
+	break;
+    case LIST_TOTAL:
+	name = "TOTAL";
+	break;
+    default:
+	name = "unknown";
+    }
+
+    LDAPDebug( LDAP_DEBUG_TRACE, "memcache 0x%p %s list:\n",
+	    cache, name, 0 );
+    for ( restmp = cache->ldmemc_resHead[index]; restmp != NULL;
+	    restmp = restmp->ldmemcr_next[index] ) {
+	LDAPDebug( LDAP_DEBUG_TRACE,
+		"    key: 0x%8.8lx, ld: 0x%p, msgid: %d\n",
+		restmp->ldmemcr_crc_key,
+		restmp->ldmemcr_req_id.ldmemcrid_ld,
+		restmp->ldmemcr_req_id.ldmemcrid_msgid );
+    }
+    LDAPDebug( LDAP_DEBUG_TRACE, "memcache 0x%p end of %s list.\n",
+	    cache, name, 0 );
+}
+#endif /* LDAP_DEBUG */
+
+/* Tells whether a cached result has expired. */
+static int
+memcache_expired(LDAPMemCache *cache, ldapmemcacheRes *pRes,
+                 unsigned long curTime)
+{
+    if (!cache->ldmemc_ttl)
+	return 0;
+
+    return ((unsigned long)difftime(
+	                     (time_t)curTime, 
+			     (time_t)(pRes->ldmemcr_timestamp)) >=
+			                          cache->ldmemc_ttl);
+}
+
+/* Operates the cache in a central place. */
+static int
+memcache_access(LDAPMemCache *cache, int mode, 
+			   void *pData1, void *pData2, void *pData3)
+{
+    int nRes = LDAP_SUCCESS;
+    unsigned long size = 0;
+
+    /* Add a new cache header to the cache. */
+    if (mode == MEMCACHE_ACCESS_ADD) {
+	unsigned long key = *((unsigned long*)pData1);
+	char *basedn = (char*)pData3;
+	ldapmemcacheRes *pRes = NULL;
+	void* hashResult = NULL;
+
+	nRes = htable_get(cache->ldmemc_resTmp, pData2, &hashResult);
+	if (nRes == LDAP_SUCCESS)
+	    return( LDAP_ALREADY_EXISTS );
+
+	pRes = (ldapmemcacheRes*)NSLDAPI_CALLOC(1, sizeof(ldapmemcacheRes));
+	if (pRes == NULL)
+	    return( LDAP_NO_MEMORY );
+
+	pRes->ldmemcr_crc_key = key;
+	pRes->ldmemcr_req_id = *((ldapmemcacheReqId*)pData2);
+	pRes->ldmemcr_basedn = (basedn ? nsldapi_strdup(basedn) : NULL);
+
+	size += sizeof(ldapmemcacheRes) + strlen(basedn) + 1;
+	nRes = memcache_adj_size(cache, size, MEMCACHE_SIZE_ENTRIES,
+	                         MEMCACHE_SIZE_ADD);
+	if (nRes == LDAP_SUCCESS)
+	    nRes = htable_put(cache->ldmemc_resTmp, pData2, (void*)pRes);
+	if (nRes == LDAP_SUCCESS)
+	    memcache_add_to_list(cache, pRes, LIST_TMP);
+	else
+	    memcache_free_entry(cache, pRes);
+    }
+    /* Append entries to an existing cache header. */
+    else if ((mode == MEMCACHE_ACCESS_APPEND) ||
+	     (mode == MEMCACHE_ACCESS_APPEND_LAST)) {
+
+	LDAPMessage *pMsg = (LDAPMessage*)pData2;
+	LDAPMessage *pCopy = NULL;
+	ldapmemcacheRes *pRes = NULL;
+	void* hashResult = NULL;
+
+	nRes = htable_get(cache->ldmemc_resTmp, pData1, &hashResult);
+	if (nRes != LDAP_SUCCESS)
+	    return nRes;
+
+	pRes = (ldapmemcacheRes*) hashResult;
+	nRes = memcache_dup_message(pMsg, pMsg->lm_msgid, 0, &pCopy, &size);
+	if (nRes != LDAP_SUCCESS) {
+	    nRes = htable_remove(cache->ldmemc_resTmp, pData1, NULL);
+	    assert(nRes == LDAP_SUCCESS);
+	    memcache_free_from_list(cache, pRes, LIST_TMP);
+	    memcache_free_entry(cache, pRes);
+	    return nRes;
+	}
+
+	nRes = memcache_adj_size(cache, size, MEMCACHE_SIZE_ENTRIES,
+	                         MEMCACHE_SIZE_ADD);
+	if (nRes != LDAP_SUCCESS) {
+	    ldap_msgfree(pCopy);
+	    nRes = htable_remove(cache->ldmemc_resTmp, pData1, NULL);
+	    assert(nRes == LDAP_SUCCESS);
+	    memcache_free_from_list(cache, pRes, LIST_TMP);
+	    memcache_free_entry(cache, pRes);
+	    return nRes;
+	}
+
+	memcache_add_res_to_list(pRes, pCopy, size);
+
+	if (mode == MEMCACHE_ACCESS_APPEND)
+	    return( LDAP_SUCCESS );
+
+	nRes = htable_remove(cache->ldmemc_resTmp, pData1, NULL);
+	assert(nRes == LDAP_SUCCESS);
+	memcache_free_from_list(cache, pRes, LIST_TMP);
+	(pRes->ldmemcr_req_id).ldmemcrid_ld = NULL;
+	(pRes->ldmemcr_req_id).ldmemcrid_msgid = -1;
+	pRes->ldmemcr_timestamp = (unsigned long)time(NULL);
+
+	if ((nRes = htable_put(cache->ldmemc_resLookup, 
+	                       (void*)&(pRes->ldmemcr_crc_key),
+                               (void*)pRes)) == LDAP_SUCCESS) {
+	    memcache_add_to_list(cache, pRes, LIST_TTL);
+	    memcache_add_to_list(cache, pRes, LIST_LRU);
+	} else {
+	    memcache_free_entry(cache, pRes);
+	}
+    }
+    /* Search for cached entries for a particular search. */
+    else if (mode == MEMCACHE_ACCESS_FIND) {
+
+	ldapmemcacheRes **ppRes = (ldapmemcacheRes**)pData2;
+
+	nRes = htable_get(cache->ldmemc_resLookup, pData1, (void**)ppRes);
+	if (nRes != LDAP_SUCCESS)
+	    return nRes;
+
+	if (!memcache_expired(cache, *ppRes, (unsigned long)time(0))) {
+	    memcache_free_from_list(cache, *ppRes, LIST_LRU);
+	    memcache_add_to_list(cache, *ppRes, LIST_LRU);
+	    return( LDAP_SUCCESS );
+	}
+
+	nRes = htable_remove(cache->ldmemc_resLookup, pData1, NULL);
+	assert(nRes == LDAP_SUCCESS);
+	memcache_free_from_list(cache, *ppRes, LIST_TTL);
+	memcache_free_from_list(cache, *ppRes, LIST_LRU);
+	memcache_free_entry(cache, *ppRes);
+	nRes = LDAP_NO_SUCH_OBJECT;
+	*ppRes = NULL;
+    }
+    /* Remove cached entries in the temporary cache. */
+    else if (mode == MEMCACHE_ACCESS_DELETE) {
+
+	void* hashResult = NULL;
+
+	if ((nRes = htable_remove(cache->ldmemc_resTmp, pData1,
+	                          &hashResult)) == LDAP_SUCCESS) {
+	    ldapmemcacheRes *pCurRes = (ldapmemcacheRes*) hashResult;
+	    memcache_free_from_list(cache, pCurRes, LIST_TMP);
+	    memcache_free_entry(cache, pCurRes);
+	}
+    }
+    /* Wipe out the temporary cache. */
+    else if (mode == MEMCACHE_ACCESS_DELETE_ALL) {
+
+	nRes = htable_removeall(cache->ldmemc_resTmp, (void*)cache);
+    }
+    /* Remove expired entries from primary cache. */
+    else if (mode == MEMCACHE_ACCESS_UPDATE) {
+
+	ldapmemcacheRes *pCurRes = cache->ldmemc_resTail[LIST_TTL];
+	unsigned long curTime = (unsigned long)time(NULL);
+
+	for (; pCurRes; pCurRes = cache->ldmemc_resTail[LIST_TTL]) {
+
+	    if (!memcache_expired(cache, pCurRes, curTime))
+		break;
+
+	    nRes = htable_remove(cache->ldmemc_resLookup, 
+		          (void*)&(pCurRes->ldmemcr_crc_key), NULL);
+	    assert(nRes == LDAP_SUCCESS);
+	    memcache_free_from_list(cache, pCurRes, LIST_TTL);
+	    memcache_free_from_list(cache, pCurRes, LIST_LRU);
+	    memcache_free_entry(cache, pCurRes);
+	}
+    }
+    /* Wipe out the primary cache. */
+    else if (mode == MEMCACHE_ACCESS_FLUSH_ALL) {
+
+	ldapmemcacheRes *pCurRes = cache->ldmemc_resHead[LIST_TTL];
+
+	nRes = htable_removeall(cache->ldmemc_resLookup, (void*)cache);
+
+	for (; pCurRes; pCurRes = cache->ldmemc_resHead[LIST_TTL]) {
+	    memcache_free_from_list(cache, pCurRes, LIST_LRU);
+	    cache->ldmemc_resHead[LIST_TTL] = 
+		      cache->ldmemc_resHead[LIST_TTL]->ldmemcr_next[LIST_TTL];
+	    memcache_free_entry(cache, pCurRes);
+	}
+	cache->ldmemc_resTail[LIST_TTL] = NULL;
+    }
+    /* Remove cached entries in both primary and temporary cache. */
+    else if ((mode == MEMCACHE_ACCESS_FLUSH) ||
+	     (mode == MEMCACHE_ACCESS_FLUSH_RESULTS)) {
+
+	int i, list_id, bDone;
+	int scope = (int)pData2;
+	char *dn = (char*)pData1;
+	char *dnTmp;
+	BerElement ber;
+	LDAPMessage *pMsg;
+	ldapmemcacheRes *pRes;
+
+	if (cache->ldmemc_basedns) {
+	    for (i = 0; cache->ldmemc_basedns[i]; i++) {
+		if ((memcache_compare_dn(cache->ldmemc_basedns[i], dn, 
+			    LDAP_SCOPE_SUBTREE) == LDAP_COMPARE_TRUE) ||
+		    (memcache_compare_dn(dn, cache->ldmemc_basedns[i], 
+			    LDAP_SCOPE_SUBTREE) == LDAP_COMPARE_TRUE))
+		    break;
+	    }
+	    if (cache->ldmemc_basedns[i] == NULL)
+		return( LDAP_SUCCESS );
+	}
+
+	for (i = 0; i < 2; i++) {
+
+	    list_id = (i == 0 ? LIST_TTL : LIST_TMP);
+
+	    for (pRes = cache->ldmemc_resHead[list_id]; pRes != NULL; 
+		 pRes = pRes->ldmemcr_next[list_id]) {
+
+		int foundentries = 0;
+
+		if ((memcache_compare_dn(pRes->ldmemcr_basedn, dn, 
+				 LDAP_SCOPE_SUBTREE) != LDAP_COMPARE_TRUE) &&
+		    (memcache_compare_dn(dn, pRes->ldmemcr_basedn, 
+				 LDAP_SCOPE_SUBTREE) != LDAP_COMPARE_TRUE))
+		    continue;
+
+		for (pMsg = pRes->ldmemcr_resHead, bDone = 0; 
+		     !bDone && pMsg; pMsg = pMsg->lm_chain) {
+
+		    if (!NSLDAPI_IS_SEARCH_ENTRY( pMsg->lm_msgtype ))
+			continue;
+		    foundentries = 1;
+		    ber = *(pMsg->lm_ber);
+		    if (ber_scanf(&ber, "{a", &dnTmp) != LBER_ERROR) {
+			bDone = (memcache_compare_dn(dnTmp, dn, scope) == 
+							    LDAP_COMPARE_TRUE);
+			ldap_memfree(dnTmp);
+		    }
+		}
+
+		/* If we're in the result flush mode, and the base matched, and
+		   there were no entries in the result, we'll flush this cache
+		   slot, as opposed to the MEMCACHE_ACCESS_FLUSH mode which does
+		   not flush negative results. */
+		if ((mode == MEMCACHE_ACCESS_FLUSH_RESULTS) && !foundentries) {
+			bDone = 1;
+		}
+
+		if (!bDone)
+		    continue;
+
+		if (list_id == LIST_TTL) {
+		    nRes = htable_remove(cache->ldmemc_resLookup, 
+			  	 (void*)&(pRes->ldmemcr_crc_key), NULL);
+		    assert(nRes == LDAP_SUCCESS);
+		    memcache_free_from_list(cache, pRes, LIST_TTL);
+		    memcache_free_from_list(cache, pRes, LIST_LRU);
+		} else {
+		    nRes = htable_remove(cache->ldmemc_resTmp, 
+				  (void*)&(pRes->ldmemcr_req_id), NULL);
+		    assert(nRes == LDAP_SUCCESS);
+		    memcache_free_from_list(cache, pRes, LIST_TMP);
+		}
+		memcache_free_entry(cache, pRes);
+	    }
+	}
+    }
+    /* Flush least recently used entries from cache */
+    else if (mode == MEMCACHE_ACCESS_FLUSH_LRU) {
+
+	ldapmemcacheRes *pRes = cache->ldmemc_resTail[LIST_LRU];
+
+	if (pRes == NULL)
+	    return LDAP_NO_SUCH_OBJECT;
+
+	LDAPDebug( LDAP_DEBUG_TRACE,
+		"memcache_access FLUSH_LRU: removing key 0x%8.8lx\n",
+		pRes->ldmemcr_crc_key, 0, 0 );
+	nRes = htable_remove(cache->ldmemc_resLookup,
+	              (void*)&(pRes->ldmemcr_crc_key), NULL);
+	assert(nRes == LDAP_SUCCESS);
+	memcache_free_from_list(cache, pRes, LIST_TTL);
+	memcache_free_from_list(cache, pRes, LIST_LRU);
+	memcache_free_entry(cache, pRes);
+    }
+    /* Unknown command */
+    else {
+	nRes = LDAP_PARAM_ERROR;
+    }
+
+    return nRes;
+}
+
+static void
+memcache_flush( LDAPMemCache *cache, char *dn, int scope, int flushresults )
+{
+    if ( !NSLDAPI_VALID_MEMCACHE_POINTER( cache )) {
+	return;
+    }
+
+    LDAP_MEMCACHE_MUTEX_LOCK( cache );
+
+    if (!dn) {
+	memcache_access(cache, MEMCACHE_ACCESS_FLUSH_ALL, NULL, NULL, NULL);
+    } else {
+	if (flushresults) {
+		memcache_access(cache, MEMCACHE_ACCESS_FLUSH_RESULTS,
+			(void*)dn, (void*)scope, NULL);
+	} else {
+		memcache_access(cache, MEMCACHE_ACCESS_FLUSH, 
+	                (void*)dn, (void*)scope, NULL);
+	}
+    }
+
+    LDAP_MEMCACHE_MUTEX_UNLOCK( cache );
+}
+
+
+#ifdef LDAP_DEBUG
+static void
+memcache_report_statistics( LDAPMemCache *cache )
+{
+    unsigned long	hitrate;
+
+    if ( cache->ldmemc_stats.ldmemcstat_tries == 0 ) {
+	hitrate = 0;
+    } else {
+	hitrate = ( 100L * cache->ldmemc_stats.ldmemcstat_hits ) /
+	    cache->ldmemc_stats.ldmemcstat_tries;
+    }
+    LDAPDebug( LDAP_DEBUG_STATS, "memcache 0x%p:\n", cache, 0, 0 );
+    LDAPDebug( LDAP_DEBUG_STATS, "    tries: %ld  hits: %ld  hitrate: %ld%%\n",
+	    cache->ldmemc_stats.ldmemcstat_tries,
+	    cache->ldmemc_stats.ldmemcstat_hits, hitrate );
+    if ( cache->ldmemc_size <= 0 ) {	/* no size limit */
+	LDAPDebug( LDAP_DEBUG_STATS, "    memory bytes used: %ld\n",
+		cache->ldmemc_size_used, 0, 0 );
+    } else {
+	LDAPDebug( LDAP_DEBUG_STATS, "    memory bytes used: %ld free: %ld\n",
+		cache->ldmemc_size_used,
+		cache->ldmemc_size - cache->ldmemc_size_used, 0 );
+    }
+}
+#endif /* LDAP_DEBUG */
+
+/************************ Hash Table Functions *****************************/
+
+/* Calculates size (# of entries) of hash table given the size limit for
+   the cache. */
+static int
+htable_calculate_size(int sizelimit)
+{
+    int i, j;
+    int size = (int)(((double)sizelimit / 
+	                (double)(sizeof(BerElement) + EXTRA_SIZE)) / 1.5);
+
+    /* Get a prime # */
+    size = (size & 0x1 ? size : size + 1);
+    for (i = 3, j = size / 2; i < j; i++) {
+	if ((size % i) == 0) {
+	    size += 2;
+	    i = 3;
+	    j = size / 2;
+	}
+    }
+
+    return size;
+}
+
+/* Returns the size in bytes of the given hash table. */
+static int
+htable_sizeinbytes(HashTable *pTable)
+{
+    if (!pTable)
+	return 0;
+
+    return (pTable->size * sizeof(HashTableNode));
+}
+
+/* Inserts an item into the hash table. */
+static int
+htable_put(HashTable *pTable, void *key, void *pData)
+{
+    int index = pTable->hashfunc(pTable->size, key);
+
+    if (index >= 0 && index < pTable->size)
+	return pTable->putdata(&(pTable->table[index].pData), key, pData);
+
+    return( LDAP_OPERATIONS_ERROR );
+}
+
+/* Retrieves an item from the hash table. */
+static int
+htable_get(HashTable *pTable, void *key, void **ppData)
+{
+    int index = pTable->hashfunc(pTable->size, key);
+
+    *ppData = NULL;
+
+    if (index >= 0 && index < pTable->size)
+	return pTable->getdata(pTable->table[index].pData, key, ppData);
+
+    return( LDAP_OPERATIONS_ERROR );
+}
+
+/* Performs a miscellaneous operation on a hash table entry. */
+static int
+htable_misc(HashTable *pTable, void *key, void *pData)
+{
+    if (pTable->miscfunc) {
+	int index = pTable->hashfunc(pTable->size, key);
+	if (index >= 0 && index < pTable->size)
+	    return pTable->miscfunc(&(pTable->table[index].pData), key, pData);
+    }
+
+    return( LDAP_OPERATIONS_ERROR );
+}
+
+/* Removes an item from the hash table. */
+static int
+htable_remove(HashTable *pTable, void *key, void **ppData)
+{
+    int index = pTable->hashfunc(pTable->size, key);
+
+    if (ppData)
+	*ppData = NULL;
+
+    if (index >= 0 && index < pTable->size)
+	return pTable->removedata(&(pTable->table[index].pData), key, ppData);
+
+    return( LDAP_OPERATIONS_ERROR );
+}
+
+/* Removes everything in the hash table. */
+static int
+htable_removeall(HashTable *pTable, void *pData)
+{
+    int i;
+
+    for (i = 0; i < pTable->size; i++)
+	pTable->clrtablenode(&(pTable->table[i].pData), pData);
+
+    return( LDAP_SUCCESS );
+}
+
+/* Creates a new hash table. */
+static int
+htable_create(int size_limit, HashFuncPtr hashf,
+			 PutDataPtr putDataf, GetDataPtr getDataf,
+			 RemoveDataPtr removeDataf, ClrTableNodePtr clrNodef,
+			 MiscFuncPtr miscOpf, HashTable **ppTable)
+{
+    size_limit = htable_calculate_size(size_limit);
+
+    if ((*ppTable = (HashTable*)NSLDAPI_CALLOC(1, sizeof(HashTable))) == NULL)
+	return( LDAP_NO_MEMORY );
+
+    (*ppTable)->table = (HashTableNode*)NSLDAPI_CALLOC(size_limit, 
+	                                       sizeof(HashTableNode));
+    if ((*ppTable)->table == NULL) {
+	NSLDAPI_FREE(*ppTable);
+	*ppTable = NULL;
+	return( LDAP_NO_MEMORY );
+    }
+
+    (*ppTable)->size = size_limit;
+    (*ppTable)->hashfunc = hashf;
+    (*ppTable)->putdata = putDataf;
+    (*ppTable)->getdata = getDataf;
+    (*ppTable)->miscfunc = miscOpf;
+    (*ppTable)->removedata = removeDataf;
+    (*ppTable)->clrtablenode = clrNodef;
+
+    return( LDAP_SUCCESS );
+}
+
+/* Destroys a hash table. */
+static int
+htable_free(HashTable *pTable)
+{
+    NSLDAPI_FREE(pTable->table);
+    NSLDAPI_FREE(pTable);
+    return( LDAP_SUCCESS );
+}
+
+/**************** Hash table callbacks for temporary cache ****************/
+
+/* Hash function */
+static int
+msgid_hashf(int table_size, void *key)
+{
+    unsigned code = (unsigned)((ldapmemcacheReqId*)key)->ldmemcrid_ld;
+    return (((code << 20) + (code >> 12)) % table_size);
+}
+
+/* Called by hash table to insert an item. */
+static int
+msgid_putdata(void **ppTableData, void *key, void *pData)
+{
+    ldapmemcacheReqId *pReqId = (ldapmemcacheReqId*)key;
+    ldapmemcacheRes *pRes = (ldapmemcacheRes*)pData;
+    ldapmemcacheRes **ppHead = (ldapmemcacheRes**)ppTableData;
+    ldapmemcacheRes *pCurRes = *ppHead;
+    ldapmemcacheRes *pPrev = NULL;
+
+    for (; pCurRes; pCurRes = pCurRes->ldmemcr_htable_next) {
+	if ((pCurRes->ldmemcr_req_id).ldmemcrid_ld == pReqId->ldmemcrid_ld)
+	    break;
+	pPrev = pCurRes;
+    }
+
+    if (pCurRes) {
+	for (; pCurRes; pCurRes = pCurRes->ldmemcr_next[LIST_TTL]) { 
+	    if ((pCurRes->ldmemcr_req_id).ldmemcrid_msgid == 
+		                               pReqId->ldmemcrid_msgid)
+		return( LDAP_ALREADY_EXISTS );
+	    pPrev = pCurRes;
+	}
+	pPrev->ldmemcr_next[LIST_TTL] = pRes;
+	pRes->ldmemcr_prev[LIST_TTL] = pPrev;
+	pRes->ldmemcr_next[LIST_TTL] = NULL;
+    } else {
+	if (pPrev)
+	    pPrev->ldmemcr_htable_next = pRes;
+	else
+	    *ppHead = pRes;
+	pRes->ldmemcr_htable_next = NULL;
+    }
+
+    return( LDAP_SUCCESS );
+}
+
+/* Called by hash table to retrieve an item. */
+static int
+msgid_getdata(void *pTableData, void *key, void **ppData)
+{
+    ldapmemcacheReqId *pReqId = (ldapmemcacheReqId*)key;
+    ldapmemcacheRes *pCurRes = (ldapmemcacheRes*)pTableData;
+
+    *ppData = NULL;
+    
+    for (; pCurRes; pCurRes = pCurRes->ldmemcr_htable_next) {
+	if ((pCurRes->ldmemcr_req_id).ldmemcrid_ld == pReqId->ldmemcrid_ld)
+	    break;
+    }
+
+    if (!pCurRes)
+	return( LDAP_NO_SUCH_OBJECT );
+
+    for (; pCurRes; pCurRes = pCurRes->ldmemcr_next[LIST_TTL]) { 
+	if ((pCurRes->ldmemcr_req_id).ldmemcrid_msgid == 
+	                                  pReqId->ldmemcrid_msgid) {
+	    *ppData = (void*)pCurRes;
+	    return( LDAP_SUCCESS );
+	}
+    }
+
+    return( LDAP_NO_SUCH_OBJECT );
+}
+
+/* Called by hash table to remove an item. */
+static int
+msgid_removedata(void **ppTableData, void *key, void **ppData)
+{
+    ldapmemcacheRes *pHead = *((ldapmemcacheRes**)ppTableData);
+    ldapmemcacheRes *pCurRes = NULL;
+    ldapmemcacheRes *pPrev = NULL;
+    ldapmemcacheReqId *pReqId = (ldapmemcacheReqId*)key;
+
+    if (ppData)
+	*ppData = NULL;
+
+    for (; pHead; pHead = pHead->ldmemcr_htable_next) {
+	if ((pHead->ldmemcr_req_id).ldmemcrid_ld == pReqId->ldmemcrid_ld)
+	    break;
+	pPrev = pHead;
+    }
+
+    if (!pHead)
+	return( LDAP_NO_SUCH_OBJECT );
+
+    for (pCurRes = pHead; pCurRes; pCurRes = pCurRes->ldmemcr_next[LIST_TTL]) { 
+	if ((pCurRes->ldmemcr_req_id).ldmemcrid_msgid == 
+	                                        pReqId->ldmemcrid_msgid)
+	    break;
+    }
+
+    if (!pCurRes)
+	return( LDAP_NO_SUCH_OBJECT );
+
+    if (ppData) {
+	pCurRes->ldmemcr_next[LIST_TTL] = NULL;
+	pCurRes->ldmemcr_prev[LIST_TTL] = NULL;
+	pCurRes->ldmemcr_htable_next = NULL;
+	*ppData = (void*)pCurRes;
+    }
+
+    if (pCurRes != pHead) {
+	if (pCurRes->ldmemcr_prev[LIST_TTL])
+	    pCurRes->ldmemcr_prev[LIST_TTL]->ldmemcr_next[LIST_TTL] = 
+	                                     pCurRes->ldmemcr_next[LIST_TTL];
+	if (pCurRes->ldmemcr_next[LIST_TTL])
+	    pCurRes->ldmemcr_next[LIST_TTL]->ldmemcr_prev[LIST_TTL] = 
+	                                     pCurRes->ldmemcr_prev[LIST_TTL];
+	return( LDAP_SUCCESS );
+    }
+
+    if (pPrev) {
+	if (pHead->ldmemcr_next[LIST_TTL]) {
+	    pPrev->ldmemcr_htable_next = pHead->ldmemcr_next[LIST_TTL];
+	    pHead->ldmemcr_next[LIST_TTL]->ldmemcr_htable_next = 
+			                   pHead->ldmemcr_htable_next;
+	} else {
+	    pPrev->ldmemcr_htable_next = pHead->ldmemcr_htable_next;
+	}
+    } else {
+	if (pHead->ldmemcr_next[LIST_TTL]) {
+	    *((ldapmemcacheRes**)ppTableData) = pHead->ldmemcr_next[LIST_TTL];
+	    pHead->ldmemcr_next[LIST_TTL]->ldmemcr_htable_next = 
+			                   pHead->ldmemcr_htable_next;
+	} else {
+	    *((ldapmemcacheRes**)ppTableData) = pHead->ldmemcr_htable_next;
+	}
+    }
+    
+    return( LDAP_SUCCESS );
+}
+
+/* Called by hash table to remove all cached entries associated to searches
+   being performed using the given ldap handle. */
+static int
+msgid_clear_ld_items(void **ppTableData, void *key, void *pData)
+{
+    LDAPMemCache *cache = (LDAPMemCache*)pData;
+    ldapmemcacheRes *pHead = *((ldapmemcacheRes**)ppTableData);
+    ldapmemcacheRes *pPrev = NULL;
+    ldapmemcacheRes *pCurRes = NULL;
+    ldapmemcacheReqId *pReqId = (ldapmemcacheReqId*)key;
+    
+    for (; pHead; pHead = pHead->ldmemcr_htable_next) {
+	if ((pHead->ldmemcr_req_id).ldmemcrid_ld == pReqId->ldmemcrid_ld)
+	    break;
+	pPrev = pHead;
+    }
+
+    if (!pHead)
+	return( LDAP_NO_SUCH_OBJECT );
+
+    if (pPrev)
+	pPrev->ldmemcr_htable_next = pHead->ldmemcr_htable_next;
+    else
+	*((ldapmemcacheRes**)ppTableData) = pHead->ldmemcr_htable_next;
+
+    for (pCurRes = pHead; pHead; pCurRes = pHead) {
+	pHead = pHead->ldmemcr_next[LIST_TTL];
+	memcache_free_from_list(cache, pCurRes, LIST_TMP);
+	memcache_free_entry(cache, pCurRes);
+    }
+
+    return( LDAP_SUCCESS );
+}
+
+/* Called by hash table for removing all items in the table. */
+static void
+msgid_clearnode(void **ppTableData, void *pData)
+{
+    LDAPMemCache *cache = (LDAPMemCache*)pData;
+    ldapmemcacheRes **ppHead = (ldapmemcacheRes**)ppTableData;
+    ldapmemcacheRes *pSubHead = *ppHead;
+    ldapmemcacheRes *pCurRes = NULL;
+
+    for (; *ppHead; pSubHead = *ppHead) {
+	ppHead = &((*ppHead)->ldmemcr_htable_next);
+	for (pCurRes = pSubHead; pSubHead; pCurRes = pSubHead) {
+	    pSubHead = pSubHead->ldmemcr_next[LIST_TTL];
+	    memcache_free_from_list(cache, pCurRes, LIST_TMP);
+	    memcache_free_entry(cache, pCurRes);
+	}
+    }
+}
+
+/********************* Hash table for primary cache ************************/
+
+/* Hash function */
+static int
+attrkey_hashf(int table_size, void *key)
+{
+    return ((*((unsigned long*)key)) % table_size);
+}
+
+/* Called by hash table to insert an item. */
+static int
+attrkey_putdata(void **ppTableData, void *key, void *pData)
+{
+    unsigned long attrkey = *((unsigned long*)key);
+    ldapmemcacheRes **ppHead = (ldapmemcacheRes**)ppTableData;
+    ldapmemcacheRes *pRes = *ppHead;
+
+    for (; pRes; pRes = pRes->ldmemcr_htable_next) {
+	if (pRes->ldmemcr_crc_key == attrkey)
+	    return( LDAP_ALREADY_EXISTS );
+    }
+
+    pRes = (ldapmemcacheRes*)pData;
+    pRes->ldmemcr_htable_next = *ppHead;
+    *ppHead = pRes;
+
+    return( LDAP_SUCCESS );
+}
+
+/* Called by hash table to retrieve an item. */
+static int
+attrkey_getdata(void *pTableData, void *key, void **ppData)
+{
+    unsigned long attrkey = *((unsigned long*)key);
+    ldapmemcacheRes *pRes = (ldapmemcacheRes*)pTableData;
+    
+    for (; pRes; pRes = pRes->ldmemcr_htable_next) {
+	if (pRes->ldmemcr_crc_key == attrkey) {
+	    *ppData = (void*)pRes;
+	    return( LDAP_SUCCESS );
+	}
+    }
+
+    *ppData = NULL;
+
+    return( LDAP_NO_SUCH_OBJECT );
+}
+
+/* Called by hash table to remove an item. */
+static int
+attrkey_removedata(void **ppTableData, void *key, void **ppData)
+{
+    unsigned long attrkey = *((unsigned long*)key);
+    ldapmemcacheRes **ppHead = (ldapmemcacheRes**)ppTableData;
+    ldapmemcacheRes *pRes = *ppHead;
+    ldapmemcacheRes *pPrev = NULL;
+    
+    for (; pRes; pRes = pRes->ldmemcr_htable_next) {
+	if (pRes->ldmemcr_crc_key == attrkey) {
+	    if (ppData)
+		*ppData = (void*)pRes;
+	    if (pPrev)
+		pPrev->ldmemcr_htable_next = pRes->ldmemcr_htable_next;
+	    else
+		*ppHead = pRes->ldmemcr_htable_next;
+	    pRes->ldmemcr_htable_next = NULL;
+	    return( LDAP_SUCCESS );
+	}
+	pPrev = pRes;
+    }
+
+    if (ppData)
+	*ppData = NULL;
+
+    return( LDAP_NO_SUCH_OBJECT );
+}
+
+/* Called by hash table for removing all items in the table. */
+static void
+attrkey_clearnode(void **ppTableData, void *pData)
+{
+    ldapmemcacheRes **ppHead = (ldapmemcacheRes**)ppTableData;
+    ldapmemcacheRes *pRes = *ppHead;
+
+    (void)pData;
+
+    for (; *ppHead; pRes = *ppHead) {
+	ppHead = &((*ppHead)->ldmemcr_htable_next);
+	pRes->ldmemcr_htable_next = NULL;
+    }
+}
+
+/***************************** CRC algorithm ********************************/
+
+/* From http://www.faqs.org/faqs/compression-faq/part1/section-25.html */
+
+/*
+ * Build auxiliary table for parallel byte-at-a-time CRC-32.
+ */
+#define NSLDAPI_CRC32_POLY 0x04c11db7     /* AUTODIN II, Ethernet, & FDDI */
+
+static nsldapi_uint_32 crc32_table[256] = { 
+    0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 
+    0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 
+    0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, 
+    0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, 
+    0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 
+    0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 
+    0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, 
+    0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, 
+    0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 
+    0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 
+    0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, 
+    0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, 
+    0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, 
+    0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 
+    0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 
+    0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, 
+    0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 
+    0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, 
+    0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, 
+    0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 
+    0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 
+    0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 
+    0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, 
+    0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, 
+    0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 
+    0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 
+    0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, 
+    0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, 
+    0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 
+    0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 
+    0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, 
+    0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, 
+    0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 
+    0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 
+    0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 
+    0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, 
+    0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 
+    0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 
+    0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, 
+    0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 
+    0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 
+    0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, 
+    0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 };
+
+/* Initialized first time "crc32()" is called. If you prefer, you can
+ * statically initialize it at compile time. [Another exercise.]
+ */
+
+static unsigned long
+crc32_convert(char *buf, int len)
+{
+    unsigned char *p;
+	nsldapi_uint_32	crc;
+
+    crc = 0xffffffff;       /* preload shift register, per CRC-32 spec */
+    for (p = (unsigned char *)buf; len > 0; ++p, --len)
+	crc = ((crc << 8) ^ crc32_table[(crc >> 24) ^ *p]) & 0xffffffff;
+
+    return (unsigned long) ~crc;    /* transmit complement, per CRC-32 spec */
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/message.c
@@ -0,0 +1,105 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+#include "ldap-int.h"
+
+int
+LDAP_CALL
+ldap_msgid( LDAPMessage *lm )
+{
+	if ( !NSLDAPI_VALID_LDAPMESSAGE_POINTER( lm )) {
+		return( -1 );
+	}
+
+	return( lm->lm_msgid );
+}
+
+int
+LDAP_CALL
+ldap_msgtype( LDAPMessage *lm )
+{
+	if ( !NSLDAPI_VALID_LDAPMESSAGE_POINTER( lm )) {
+		return( -1 );
+	}
+
+	return( lm->lm_msgtype );
+}
+
+
+LDAPMessage *
+LDAP_CALL
+ldap_first_message( LDAP *ld, LDAPMessage *chain )
+{
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( NULLMSG );		/* punt */
+	}
+
+	return( chain );
+}
+
+
+LDAPMessage *
+LDAP_CALL
+ldap_next_message( LDAP *ld, LDAPMessage *msg )
+{
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( NULLMSG );		/* punt */
+	}
+
+	if ( msg == NULLMSG || msg->lm_chain == NULLMSG ) {
+		return( NULLMSG );
+	}
+
+	return( msg->lm_chain );
+}
+
+
+int
+LDAP_CALL
+ldap_count_messages( LDAP *ld, LDAPMessage *chain )
+{
+	int	i;
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( -1 );
+	}
+
+	for ( i = 0; chain != NULL; chain = chain->lm_chain ) {
+		i++;
+	}
+
+	return( i );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/modify.c
@@ -0,0 +1,226 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ *  Copyright (c) 1990 Regents of the University of Michigan.
+ *  All rights reserved.
+ */
+/*
+ *  modify.c
+ */
+
+#if 0
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+/*
+ * ldap_modify - initiate an ldap modify operation.  Parameters:
+ *
+ *	ld		LDAP descriptor
+ *	dn		DN of the object to modify
+ *	mods		List of modifications to make.  This is null-terminated
+ *			array of struct ldapmod's, specifying the modifications
+ *			to perform.
+ *
+ * Example:
+ *	LDAPMod	*mods[] = { 
+ *			{ LDAP_MOD_ADD, "cn", { "babs jensen", "babs", 0 } },
+ *			{ LDAP_MOD_REPLACE, "sn", { "jensen", 0 } },
+ *			0
+ *		}
+ *	msgid = ldap_modify( ld, dn, mods );
+ */
+int
+LDAP_CALL
+ldap_modify( LDAP *ld, const char *dn, LDAPMod **mods )
+{
+	int		msgid;
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_modify\n", 0, 0, 0 );
+
+	if ( ldap_modify_ext( ld, dn, mods, NULL, NULL, &msgid )
+	    == LDAP_SUCCESS ) {
+		return( msgid );
+	} else {
+		return( -1 );	/* error is in ld handle */
+	}
+}
+
+int
+LDAP_CALL
+ldap_modify_ext( LDAP *ld, const char *dn, LDAPMod **mods,
+    LDAPControl **serverctrls, LDAPControl **clientctrls, int *msgidp )
+{
+	BerElement	*ber;
+	int		i, rc, lderr;
+
+	/*
+	 * A modify request looks like this:
+	 *	ModifyRequet ::= SEQUENCE {
+	 *		object		DistinguishedName,
+	 *		modifications	SEQUENCE OF SEQUENCE {
+	 *			operation	ENUMERATED {
+	 *				add	(0),
+	 *				delete	(1),
+	 *				replace	(2)
+	 *			},
+	 *			modification	SEQUENCE {
+	 *				type	AttributeType,
+	 *				values	SET OF AttributeValue
+	 *			}
+	 *		}
+	 *	}
+	 */
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_modify_ext\n", 0, 0, 0 );
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( LDAP_PARAM_ERROR );
+	}
+	if ( !NSLDAPI_VALID_LDAPMESSAGE_POINTER( msgidp )) 
+        {
+		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+		return( LDAP_PARAM_ERROR );
+	}
+        
+	if ( !NSLDAPI_VALID_NONEMPTY_LDAPMOD_ARRAY( mods )) {
+		lderr = LDAP_PARAM_ERROR;
+		LDAP_SET_LDERRNO( ld, lderr, NULL, NULL );
+		return( lderr );
+	}
+	if ( dn == NULL ) {
+		dn = "";
+	}
+
+	LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK );
+	*msgidp = ++ld->ld_msgid;
+	LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK );
+
+	/* see if we should add to the cache */
+	if ( ld->ld_cache_on && ld->ld_cache_modify != NULL ) {
+		LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK );
+		if ( (rc = (ld->ld_cache_modify)( ld, *msgidp, LDAP_REQ_MODIFY,
+		    dn, mods )) != 0 ) {
+			*msgidp = rc;
+			LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK );
+			return( LDAP_SUCCESS );
+		}
+		LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+	}
+
+	/* create a message to send */
+	if (( lderr = nsldapi_alloc_ber_with_options( ld, &ber ))
+	    != LDAP_SUCCESS ) {
+		return( lderr );
+	}
+
+	if ( ber_printf( ber, "{it{s{", *msgidp, LDAP_REQ_MODIFY, dn )
+	    == -1 ) {
+		lderr = LDAP_ENCODING_ERROR;
+		LDAP_SET_LDERRNO( ld, lderr, NULL, NULL );
+		ber_free( ber, 1 );
+		return( lderr );
+	}
+
+	/* for each modification to be performed... */
+	for ( i = 0; mods[i] != NULL; i++ ) {
+		if (( mods[i]->mod_op & LDAP_MOD_BVALUES) != 0 ) {
+			rc = ber_printf( ber, "{e{s[V]}}",
+			    mods[i]->mod_op & ~LDAP_MOD_BVALUES,
+			    mods[i]->mod_type, mods[i]->mod_bvalues );
+		} else {
+			rc = ber_printf( ber, "{e{s[v]}}", mods[i]->mod_op,
+			    mods[i]->mod_type, mods[i]->mod_values );
+		}
+
+		if ( rc == -1 ) {
+			lderr = LDAP_ENCODING_ERROR;
+			LDAP_SET_LDERRNO( ld, lderr, NULL, NULL );
+			ber_free( ber, 1 );
+			return( lderr );
+		}
+	}
+
+	if ( ber_printf( ber, "}}" ) == -1 ) {
+		lderr = LDAP_ENCODING_ERROR;
+		LDAP_SET_LDERRNO( ld, lderr, NULL, NULL );
+		ber_free( ber, 1 );
+		return( lderr );
+	}
+
+	if (( lderr = nsldapi_put_controls( ld, serverctrls, 1, ber ))
+	    != LDAP_SUCCESS ) {
+		ber_free( ber, 1 );
+		return( lderr );
+	}
+
+	/* send the message */
+	rc = nsldapi_send_initial_request( ld, *msgidp, LDAP_REQ_MODIFY,
+		(char *)dn, ber );
+	*msgidp = rc;
+	return( rc < 0 ? LDAP_GET_LDERRNO( ld, NULL, NULL ) : LDAP_SUCCESS );
+}
+
+int
+LDAP_CALL
+ldap_modify_s( LDAP *ld, const char *dn, LDAPMod **mods )
+{
+	return( ldap_modify_ext_s( ld, dn, mods, NULL, NULL ));
+}
+
+int
+LDAP_CALL
+ldap_modify_ext_s( LDAP *ld, const char *dn, LDAPMod **mods,
+    LDAPControl **serverctrls, LDAPControl **clientctrls )
+{
+	int		msgid, err;
+	LDAPMessage	*res;
+
+	if (( err = ldap_modify_ext( ld, dn, mods, serverctrls, clientctrls,
+	    &msgid )) != LDAP_SUCCESS ) {
+		return( err );
+	}
+
+	if ( ldap_result( ld, msgid, 1, (struct timeval *)NULL, &res ) == -1 ) {
+		return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+	}
+
+	return( ldap_result2error( ld, res, 1 ) );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/mozock.c
@@ -0,0 +1,714 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+#ifdef _WINDOWS
+#define FD_SETSIZE	30000
+#endif
+
+#include <windows.h>
+#include <winsock.h>
+#include <string.h>
+
+//	Purpose of this file is to implement an intermediate layer to our network
+//		services, the winsock.
+//	This intermediate layer will be able to function with and without a working
+//		winsock being present.
+//	The attempt to activate the winsock happens as would normally be expected,
+//              through the calling application's entry point to us, WSAStartup.
+
+
+//	Name of the winsock we would like to load.
+//	Diffs between OSs, Win32s is out in the cold if running 32 bits unless
+//		they also have a winsock name wsock32.dll.
+#ifndef _WIN32
+#define SZWINSOCK "winsock.dll"
+#else
+#define SZWINSOCK "wsock32.dll"
+#endif
+
+//	Here is the enumeration for the winsock functions we have currently
+//		overridden (needed to run).  Add more when needed.
+//	We use these to access proc addresses, and to hold a table of strings
+//		to obtain the proc addresses.
+enum SockProc	{
+	sp_WSAAsyncGetHostByName = 0,
+	sp_WSAAsyncSelect,
+	sp_WSACleanup,
+	sp_WSAGetLastError,
+	sp_WSASetLastError,
+	sp_WSAStartup,
+	sp___WSAFDIsSet,
+	sp_accept,
+	sp_bind,
+	sp_closesocket,
+	sp_connect,
+	sp_gethostbyname,
+	sp_gethostbyaddr,
+	sp_gethostname,
+	sp_getpeername,
+	sp_getsockname,
+	sp_getsockopt,
+	sp_getprotobyname,
+	sp_htonl,
+	sp_htons,
+	sp_inet_addr,
+	sp_ioctlsocket,
+	sp_listen,
+	sp_ntohl,
+	sp_ntohs,
+	sp_recv,
+	sp_select,
+	sp_send,
+	sp_setsockopt,
+	sp_shutdown,
+	sp_socket,
+	sp_inet_ntoa,
+
+	sp_MaxProcs	//	Total count.
+};
+
+//	Array of function names used in GetProcAddress to fill in our
+//		proc array when needed.
+//	This array must match the enumerations exactly.
+char *spName[(int)sp_MaxProcs] =	{
+        "WSAAsyncGetHostByName",
+        "WSAAsyncSelect",
+        "WSACleanup",
+        "WSAGetLastError",
+        "WSASetLastError",
+        "WSAStartup",
+        "__WSAFDIsSet",
+        "accept",
+        "bind",
+        "closesocket",
+        "connect",
+        "gethostbyname",
+        "gethostbyaddr",
+        "gethostname",
+        "getpeername",
+        "getsockname",
+        "getsockopt",
+        "getprotobyname",
+        "htonl",
+        "htons",
+        "inet_addr",
+        "ioctlsocket",
+        "listen",
+        "ntohl",
+        "ntohs",
+        "recv",
+        "select",
+        "send",
+        "setsockopt",
+        "shutdown",
+        "socket",
+        "inet_ntoa"
+};
+
+//	Array of proc addresses to the winsock functions.
+//      These can be NULL, indicating their absence (as in the case we couldn't
+//              load the winsock.dll or one of the functions wasn't loaded).
+//	The procs assigned in must corellate with the enumerations exactly.
+FARPROC spArray[(int)sp_MaxProcs];
+
+//	Typedef all the different types of functions that we must cast the
+//		procs to in order to call without the compiler barfing.
+//	Prefix is always sp.
+//	Retval is next, spelled out.
+//	Parameters in their order are next, spelled out.
+typedef int (PASCAL FAR *sp_int_WORD_LPWSADATA)(WORD, LPWSADATA);
+typedef int (PASCAL FAR *sp_int_void)(void);
+typedef HANDLE (PASCAL FAR *sp_HANDLE_HWND_uint_ccharFARp_charFARp_int)(HWND, unsigned int, const char FAR *, char FAR *, int);
+typedef int (PASCAL FAR *sp_int_SOCKET_HWND_uint_long)(SOCKET, HWND, unsigned int, long);
+typedef void (PASCAL FAR *sp_void_int)(int);
+typedef int (PASCAL FAR *sp_int_SOCKET_fdsetFARp)(SOCKET, fd_set FAR *);
+typedef SOCKET(PASCAL FAR *sp_SOCKET_SOCKET_sockaddrFARp_intFARp)(SOCKET, struct sockaddr FAR *, int FAR *);
+typedef int (PASCAL FAR *sp_int_SOCKET_csockaddrFARp_int)(SOCKET, const struct sockaddr FAR *, int);
+typedef int (PASCAL FAR *sp_int_SOCKET)(SOCKET);
+typedef struct hostent FAR *(PASCAL FAR *sp_hostentFARp_ccharFARp)(const char FAR *);
+typedef struct hostent FAR *(PASCAL FAR *sp_hostentFARp_ccharFARp_int_int)(const char FAR *, int, int);
+typedef int (PASCAL FAR *sp_int_charFARp_int)(char FAR *, int);
+typedef int (PASCAL FAR *sp_int_SOCKET_sockaddrFARp_intFARp)(SOCKET, struct sockaddr FAR *, int FAR *);
+typedef int (PASCAL FAR *sp_int_SOCKET_int_int_charFARp_intFARp)(SOCKET, int, int, char FAR *, int FAR *);
+typedef u_long (PASCAL FAR *sp_ulong_ulong)(u_long);
+typedef u_short (PASCAL FAR *sp_ushort_ushort)(u_short);
+typedef unsigned long (PASCAL FAR *sp_ulong_ccharFARp)(const char FAR *);
+typedef int (PASCAL FAR *sp_int_SOCKET_long_ulongFARp)(SOCKET, long, u_long FAR *);
+typedef int (PASCAL FAR *sp_int_SOCKET_int)(SOCKET, int);
+typedef int (PASCAL FAR *sp_int_SOCKET_charFARp_int_int)(SOCKET, char FAR *, int, int);
+typedef int (PASCAL FAR *sp_int_int_fdsetFARp_fdsetFARp_fdsetFARp_ctimevalFARp)(int,fd_set FAR *,fd_set FAR *,fd_set FAR *,const struct timeval FAR*);
+typedef int (PASCAL FAR *sp_int_SOCKET_ccharFARp_int_int)(SOCKET, const char FAR *, int, int);
+typedef int (PASCAL FAR *sp_int_SOCKET_int_int_ccharFARp_int)(SOCKET, int, int, const char FAR *, int);
+typedef SOCKET (PASCAL FAR *sp_SOCKET_int_int_int)(int, int, int);
+typedef char FAR * (PASCAL FAR *sp_charFARp_in_addr)(struct in_addr in);
+typedef struct protoent FAR * (PASCAL FAR *sp_protoentFARcchar)(const char FAR *);
+
+//	Handle to the winsock, if loaded.
+HINSTANCE hWinsock = NULL;
+
+#ifndef _WIN32
+//	Last error code for the winsock.
+int ispError = 0;
+#endif
+
+
+BOOL IsWinsockLoaded (int sp)
+{
+	if (hWinsock == NULL)
+	{
+		WSADATA wsaData;
+#ifdef _WIN32
+		static LONG sc_init = 0;
+		static DWORD sc_done = 0;
+		static CRITICAL_SECTION sc;
+#endif
+		/* We need to wait here because another thread might be
+		 in the routine already */
+#ifdef _WIN32
+		if (0 == InterlockedExchange(&sc_init,1)) {
+			InitializeCriticalSection(&sc);
+			sc_done = 1;
+		}
+		while (0 == sc_done) Sleep(0);
+		EnterCriticalSection(&sc);
+		if (hWinsock == NULL) {
+#endif
+			WSAStartup(0x0101, &wsaData);
+#ifdef _WIN32
+		}
+		LeaveCriticalSection(&sc);
+#endif
+	}
+//	Quick macro to tell if the winsock has actually loaded for a particular
+//		function.
+//  Debug version is a little more strict to make sure you get the names right.
+#ifdef DEBUG
+	return hWinsock != NULL && spArray[(int)(sp)] != NULL;
+#else //  A little faster
+	return hWinsock != NULL;
+#endif
+}
+
+//	Here are the functions that we have taken over by not directly linking
+//		with the winsock import library or importing through the def file.
+
+/* In win16 we simulate blocking commands as follows.  Prior to issuing the
+ * command we make the socket not-blocking (WSAAsyncSelect does that).
+ * We then issue the command and see if it would have blocked.	If so, we
+ * yield the processor and go to sleep until an event occurs that unblocks
+ * us (WSAAsyncSelect allowed us to register what that condition is).  We
+ * keep repeating until we do not get a would-block indication when issuing
+ * the command.  At that time we unregister the notification condition and
+ * return the result of the command to the caller.
+ */
+
+//#ifndef _WIN32
+#if 0
+#define NON_BLOCKING(command,condition,index,type)			      \
+    type iret;								      \
+    HWND hWndFrame = AfxGetApp()->m_pMainWnd->m_hWnd;			      \
+    while (TRUE) {							      \
+	if (WSAAsyncSelect(s, hWndFrame, msg_NetActivity, condition)	      \
+		== SOCKET_ERROR) {					      \
+	    break;							      \
+	}								      \
+	if(IsWinsockLoaded(index)) {					      \
+	    iret=command;						      \
+	    if (!(iret==SOCKET_ERROR && WSAGetLastError()==WSAEWOULDBLOCK)) { \
+		WSAAsyncSelect(s, hWndFrame, msg_NetActivity, 0);	      \
+		return iret;						      \
+	    }								      \
+	    PR_Yield(); 						      \
+	} else {							      \
+	    break;							      \
+	}								      \
+    }
+#else
+#define NON_BLOCKING(command,condition,index,type)			      \
+    if(IsWinsockLoaded(index)) {					      \
+	return command; 						      \
+    }
+#endif
+
+int PASCAL FAR WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData)	{
+	//	Our default return value is failure, though we change this regardless.
+	int iRetval = WSAVERNOTSUPPORTED;
+	HINSTANCE MyHandle;
+
+	//	Before doing anything, clear out our proc array.
+	memset(spArray, 0, sizeof(spArray));
+
+	//	attempt to load the real winsock.
+	MyHandle = LoadLibrary(SZWINSOCK);
+#ifdef _WIN32
+	if(MyHandle != NULL)	{
+#else
+	if(MyHandle > HINSTANCE_ERROR)	{
+#endif
+		//	Winsock was loaded.
+		//	Get the proc addresses for each needed function next.
+		int spTraverse;
+		for(spTraverse = 0; spTraverse < (int)sp_MaxProcs; spTraverse++)	{
+			spArray[spTraverse] = GetProcAddress(MyHandle, spName[spTraverse]);
+			if ( NULL == spArray[spTraverse] )
+				return iRetval;//	Bad winsock?  Bad function name?
+		}
+
+		hWinsock = MyHandle;
+		//	AllRight, attempt to make our first proxied call.
+		if(IsWinsockLoaded(sp_WSAStartup))	{
+			iRetval = ((sp_int_WORD_LPWSADATA)spArray[sp_WSAStartup])(wVersionRequested, lpWSAData);
+		}
+
+		//	If the return value is still an error at this point, we unload the DLL,
+		//		so that we can act as though nothing happened and the user
+		//		gets no network access.
+		if(iRetval != 0)	{
+			//	Clear out our proc array.
+			memset(spArray, 0, sizeof(spArray));
+
+			//	Free up the winsock.
+			FreeLibrary(MyHandle);
+			MyHandle = NULL;
+		}
+	}
+#ifndef _WIN32
+	else	{
+		//	Failed to load.
+		//	Set this to NULL so it is clear.
+		hWinsock = NULL;
+	}
+#endif
+
+
+        //      Check our return value, if it isn't success, then we need to fake
+	//		our own winsock implementation.
+	if(iRetval != 0)	{
+		//	We always return success.
+		iRetval = 0;
+
+		//	Fill in the structure.
+		//	Return the version requested as the version supported.
+		lpWSAData->wVersion = wVersionRequested;
+		lpWSAData->wHighVersion = wVersionRequested;
+
+		//	Fill in a discription.
+                strcpy(lpWSAData->szDescription, "Mozock DLL internal implementation.");
+                strcpy(lpWSAData->szSystemStatus, "Winsock running, allowing no network access.");
+
+		//	Report a nice round number for sockets and datagram sizes.
+		lpWSAData->iMaxSockets = 4096;
+		lpWSAData->iMaxUdpDg = 4096;
+
+		//	No vendor information.
+		lpWSAData->lpVendorInfo = NULL;
+	}
+
+	return(iRetval);
+}
+
+int PASCAL FAR WSACleanup(void) {
+	int iRetval = 0;
+
+	//	Handling normally or internally.
+	// When IsWinsockLoaded() is called and hWinsock is NULL, it winds up calling WSAStartup
+	// which wedges rpcrt4.dll on win95 with some winsock implementations. Bug: 81359.
+	if(hWinsock && IsWinsockLoaded(sp_WSACleanup))  {
+		//	Call their cleanup routine.
+		//	We could set the return value here, but it is meaning less.
+		//	We always return success.
+		iRetval = ((sp_int_void)spArray[sp_WSACleanup])();
+		//ASSERT(iRetval == 0);
+		iRetval = 0;
+	}
+
+	//	Wether or not it succeeded, we free off the library here.
+	//	Clear out our proc table too.
+	memset(spArray, 0, sizeof(spArray));
+	if(hWinsock != NULL)	{
+		FreeLibrary(hWinsock);
+		hWinsock = NULL;
+	}
+
+	return(iRetval);
+}
+
+HANDLE PASCAL FAR WSAAsyncGetHostByName(HWND hWnd, unsigned int wMsg, const char FAR *name, char FAR *buf, int buflen)	{
+	// Normal or shim.
+	if(IsWinsockLoaded(sp_WSAAsyncGetHostByName))	{
+		return(((sp_HANDLE_HWND_uint_ccharFARp_charFARp_int)spArray[sp_WSAAsyncGetHostByName])(hWnd, wMsg, name, buf, buflen));
+	}
+
+	//	Must return error here.
+	//	Set our last error value to be that the net is down.
+	WSASetLastError(WSAENETDOWN);
+	return(NULL);
+}
+
+int PASCAL FAR WSAAsyncSelect(SOCKET s, HWND hWnd, unsigned int wMsg, long lEvent)	{
+	//	Normal or shim.
+	if(IsWinsockLoaded(sp_WSAAsyncSelect))	{
+		return(((sp_int_SOCKET_HWND_uint_long)spArray[sp_WSAAsyncSelect])(s, hWnd, wMsg, lEvent));
+	}
+
+	//	Must return error here.
+	WSASetLastError(WSAENETDOWN);
+	return(SOCKET_ERROR);
+}
+
+int PASCAL FAR WSAGetLastError(void)	{
+	//	See if someone else can handle.
+	if(IsWinsockLoaded(sp_WSAGetLastError)) {
+		return(((sp_int_void)spArray[sp_WSAGetLastError])());
+	}
+
+#ifndef _WIN32
+	{
+		//	Fake it.
+		int iRetval = ispError;
+		ispError = 0;
+		return(iRetval);
+	}
+#else
+	//	Use default OS handler.
+	return(GetLastError());
+#endif
+}
+
+void PASCAL FAR WSASetLastError(int iError)	{
+	//	See if someone else can handle.
+	if(IsWinsockLoaded(sp_WSASetLastError)) {
+		((sp_void_int)spArray[sp_WSASetLastError])(iError);
+		return;
+	}
+
+#ifndef _WIN32
+	//	Fake it.
+	ispError = iError;
+	return;
+#else
+	//	Use default OS handler.
+	SetLastError(iError);
+	return;
+#endif
+}
+
+int PASCAL FAR __WSAFDIsSet(SOCKET fd, fd_set FAR *set) {
+	int i;
+
+	//	See if someone else will handle.
+	if(IsWinsockLoaded(sp___WSAFDIsSet))	{
+		return(((sp_int_SOCKET_fdsetFARp)spArray[sp___WSAFDIsSet])(fd, set));
+	}
+
+	//	Default implementation.
+	i = set->fd_count;
+	while (i--)	{
+		if (set->fd_array[i] == fd)	{
+			return 1;
+		}
+	}
+	return 0;
+}
+
+SOCKET PASCAL FAR accept(SOCKET s, struct sockaddr FAR *addr, int FAR *addrlen) {
+	//	Internally or shim
+	NON_BLOCKING(
+	    (((sp_SOCKET_SOCKET_sockaddrFARp_intFARp)spArray[sp_accept])(s, addr, addrlen)),
+	    FD_ACCEPT, sp_accept, SOCKET);
+
+	//	Fail.
+	WSASetLastError(WSAENETDOWN);
+	return(INVALID_SOCKET);
+}
+
+int PASCAL FAR bind(SOCKET s, const struct sockaddr FAR *name, int namelen)	{
+	//	Internally or shim
+	if(IsWinsockLoaded(sp_bind))	{
+		return(((sp_int_SOCKET_csockaddrFARp_int)spArray[sp_bind])(s, name, namelen));
+	}
+
+	//	Fail.
+	WSASetLastError(WSAENETDOWN);
+	return(SOCKET_ERROR);
+}
+
+int PASCAL FAR closesocket(SOCKET s)	{
+	//	Internally or shim.
+	NON_BLOCKING(
+	    (((sp_int_SOCKET)spArray[sp_closesocket])(s)),
+	    FD_CLOSE, sp_closesocket, int);
+
+	//	Error.
+	WSASetLastError(WSAENETDOWN);
+	return(SOCKET_ERROR);
+}
+
+int PASCAL FAR connect(SOCKET s, const struct sockaddr FAR *name, int namelen)	{
+	//	Internally or shim.
+	if(IsWinsockLoaded(sp_connect)) {
+		/* This could block and so it would seem that the NON_BLOCK
+		 * macro should be used here.  However it was causing a crash
+		 * and so it was decided to allow blocking here instead
+		 */
+		return (((sp_int_SOCKET_csockaddrFARp_int)spArray[sp_connect])(s, name, namelen));
+	}
+
+	//	Err.
+	WSASetLastError(WSAENETDOWN);
+	return(SOCKET_ERROR);
+}
+
+struct hostent FAR * PASCAL FAR gethostbyname(const char FAR *name)	{
+	if(IsWinsockLoaded(sp_gethostbyname))	{
+		return(((sp_hostentFARp_ccharFARp)spArray[sp_gethostbyname])(name));
+	}
+
+	WSASetLastError(WSAENETDOWN);
+	return(NULL);
+}
+
+struct hostent FAR * PASCAL FAR gethostbyaddr(const char FAR *addr, int len, int type)	{
+	if(IsWinsockLoaded(sp_gethostbyaddr))	{
+		return(((sp_hostentFARp_ccharFARp_int_int)spArray[sp_gethostbyaddr])(addr, len, type));
+	}
+
+	WSASetLastError(WSAENETDOWN);
+	return(NULL);
+}
+
+int PASCAL FAR gethostname(char FAR *name, int namelen) {
+	if(IsWinsockLoaded(sp_gethostname))	{
+		return(((sp_int_charFARp_int)spArray[sp_gethostname])(name, namelen));
+	}
+
+	WSASetLastError(WSAENETDOWN);
+	return(SOCKET_ERROR);
+}
+
+int PASCAL FAR getpeername(SOCKET s, struct sockaddr FAR *name, int FAR *namelen)	{
+	if(IsWinsockLoaded(sp_getpeername))	{
+		return(((sp_int_SOCKET_sockaddrFARp_intFARp)spArray[sp_getpeername])(s, name, namelen));
+	}
+
+	WSASetLastError(WSAENETDOWN);
+	return(SOCKET_ERROR);
+}
+
+int PASCAL FAR getsockname(SOCKET s, struct sockaddr FAR *name, int FAR *namelen)	{
+	if(IsWinsockLoaded(sp_getsockname))	{
+		return(((sp_int_SOCKET_sockaddrFARp_intFARp)spArray[sp_getsockname])(s, name, namelen));
+	}
+
+	WSASetLastError(WSAENETDOWN);
+	return(SOCKET_ERROR);
+}
+
+int PASCAL FAR getsockopt(SOCKET s, int level, int optname, char FAR *optval, int FAR *optlen)	{
+	if(IsWinsockLoaded(sp_getsockopt))	{
+		return(((sp_int_SOCKET_int_int_charFARp_intFARp)spArray[sp_getsockopt])(s, level, optname, optval, optlen));
+	}
+
+	WSASetLastError(WSAENETDOWN);
+	return(SOCKET_ERROR);
+}
+
+struct protoent FAR * PASCAL getprotobyname(const char FAR * name) {
+	if(IsWinsockLoaded(sp_getprotobyname))	{
+		return(((sp_protoentFARcchar)spArray[sp_getprotobyname])(name));
+	}
+
+	WSASetLastError(WSAENETDOWN);
+	return NULL;
+}
+
+u_long PASCAL FAR htonl(u_long hostlong)	{
+	if(IsWinsockLoaded(sp_htonl))	{
+		return(((sp_ulong_ulong)spArray[sp_htonl])(hostlong));
+	}
+
+#ifndef _WIN32
+	return
+	    (((hostlong&0xff)<<24) + ((hostlong&0xff00)<<8) +
+	     ((hostlong&0xff0000)>>8) + ((hostlong&0xff000000)>>24));
+
+#else
+	//	Just return what was passed in.
+	return(hostlong);
+#endif
+}
+
+u_short PASCAL FAR htons(u_short hostshort)	{
+	if(IsWinsockLoaded(sp_htons))	{
+		return(((sp_ushort_ushort)spArray[sp_htons])(hostshort));
+	}
+
+#ifndef _WIN32
+	return (((hostshort&0xff)<<8) + ((hostshort&0xff00)>>8));
+
+#else
+	//	Just return what was passed in.
+	return(hostshort);
+#endif
+}
+
+u_long PASCAL FAR ntohl(u_long hostlong)	{
+	if(IsWinsockLoaded(sp_ntohl))	{
+		return(((sp_ulong_ulong)spArray[sp_ntohl])(hostlong));
+	}
+
+#ifndef _WIN32
+	return
+	    (((hostlong&0xff)<<24) + ((hostlong&0xff00)<<8) +
+	     ((hostlong&0xff0000)>>8) + ((hostlong&0xff000000)>>24));
+
+#else
+	//	Just return what was passed in.
+	return(hostlong);
+#endif
+}
+
+u_short PASCAL FAR ntohs(u_short hostshort)	{
+	if(IsWinsockLoaded(sp_ntohs))	{
+		return(((sp_ushort_ushort)spArray[sp_ntohs])(hostshort));
+	}
+
+#ifndef _WIN32
+	return (((hostshort&0xff)<<8) + ((hostshort&0xff00)>>8));
+
+#else
+	//	Just return what was passed in.
+	return(hostshort);
+#endif
+}
+
+unsigned long PASCAL FAR inet_addr(const char FAR *cp)	{
+	if(IsWinsockLoaded(sp_inet_addr))	{
+		return(((sp_ulong_ccharFARp)spArray[sp_inet_addr])(cp));
+	}
+
+	return(INADDR_NONE);
+}
+
+int PASCAL FAR ioctlsocket(SOCKET s, long cmd, u_long FAR *argp)	{
+	if(IsWinsockLoaded(sp_ioctlsocket))	{
+		return(((sp_int_SOCKET_long_ulongFARp)spArray[sp_ioctlsocket])(s, cmd, argp));
+	}
+
+	WSASetLastError(WSAENETDOWN);
+	return(SOCKET_ERROR);
+}
+
+int PASCAL FAR listen(SOCKET s, int backlog)	{
+	if(IsWinsockLoaded(sp_listen))	{
+		return(((sp_int_SOCKET_int)spArray[sp_listen])(s, backlog));
+	}
+
+	WSASetLastError(WSAENETDOWN);
+	return(SOCKET_ERROR);
+}
+
+int PASCAL FAR recv(SOCKET s, char FAR *buf, int len, int flags)	{
+	NON_BLOCKING(
+	    (((sp_int_SOCKET_charFARp_int_int)spArray[sp_recv])(s, buf, len, flags)),
+	    FD_READ, sp_recv, int);
+
+	WSASetLastError(WSAENETDOWN);
+	return(SOCKET_ERROR);
+}
+
+int PASCAL FAR select(int nfds, fd_set FAR *readfds, fd_set FAR *writefds, fd_set FAR *exceptfds, const struct timeval FAR *timeout)	{
+    //  If there's nothing to do, stop now before we go off into dll land.
+    //	Optimization, boyz.
+    if((readfds && readfds->fd_count) || (writefds && writefds->fd_count) || (exceptfds && exceptfds->fd_count))    {
+	    if(IsWinsockLoaded(sp_select))	{
+			return(((sp_int_int_fdsetFARp_fdsetFARp_fdsetFARp_ctimevalFARp)spArray[sp_select])(nfds,readfds,writefds,exceptfds,timeout));
+	    }
+
+	    WSASetLastError(WSAENETDOWN);
+	    return(SOCKET_ERROR);
+    }
+
+    //	No need to go to the DLL, there is nothing to do.
+    return(0);
+}
+
+int PASCAL FAR send(SOCKET s, const char FAR *buf, int len, int flags)	{
+	NON_BLOCKING(
+
+	    (((sp_int_SOCKET_ccharFARp_int_int)spArray[sp_send])(s, buf, len, flags)),
+	    FD_WRITE, sp_send, int);
+
+	WSASetLastError(WSAENETDOWN);
+	return(SOCKET_ERROR);
+}
+
+int PASCAL FAR setsockopt(SOCKET s, int level, int optname, const char FAR *optval, int optlen) {
+	if(IsWinsockLoaded(sp_setsockopt))	{
+		return(((sp_int_SOCKET_int_int_ccharFARp_int)spArray[sp_setsockopt])(s, level, optname, optval, optlen));
+	}
+
+	WSASetLastError(WSAENETDOWN);
+	return(SOCKET_ERROR);
+}
+
+int PASCAL FAR shutdown(SOCKET s, int how)	{
+	if(IsWinsockLoaded(sp_shutdown))	{
+		return(((sp_int_SOCKET_int)spArray[sp_shutdown])(s, how));
+	}
+
+	WSASetLastError(WSAENETDOWN);
+	return(SOCKET_ERROR);
+}
+
+SOCKET PASCAL FAR socket(int af, int type, int protocol)	{
+	if(IsWinsockLoaded(sp_socket))	{
+		return(((sp_SOCKET_int_int_int)spArray[sp_socket])(af, type, protocol));
+	}
+
+	WSASetLastError(WSAENETDOWN);
+	return(INVALID_SOCKET);
+}
+
+char FAR * PASCAL FAR inet_ntoa(struct in_addr in) {
+	if(IsWinsockLoaded(sp_inet_ntoa))	{
+		return ((sp_charFARp_in_addr)spArray[sp_inet_ntoa])(in);
+	}
+
+	WSASetLastError(WSAENETDOWN);
+	return NULL;
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/nsprthreadtest.c
@@ -0,0 +1,621 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+#include <nspr.h>
+#include <stdio.h>
+#include <ldap.h>
+
+#define NAME		"cn=Directory Manager"
+#define PASSWORD	"secret99"
+#define BASE		"dc=example,dc=com"
+
+static int simplebind( LDAP *ld, char *msg, int tries );
+static void search_thread( void * );
+static void modify_thread( void * );
+static void add_thread( void * );
+static void delete_thread( void * );
+static void set_ld_error();
+static int  get_ld_error();
+static void set_errno();
+static int  get_errno();
+static void tsd_setup();
+static void *my_mutex_alloc( void );
+static void my_mutex_free( void * );
+static int my_mutex_lock( void * );
+static int my_mutex_unlock( void * );
+static LDAPHostEnt *my_gethostbyname( const char *name, LDAPHostEnt *result,
+	char *buffer, int buflen, int *statusp, void *extradata );
+static LDAPHostEnt *my_gethostbyaddr( const char *addr, int length,
+	int type, LDAPHostEnt *result, char *buffer, int buflen,
+	int *statusp, void *extradata );
+static LDAPHostEnt *copyPRHostEnt2LDAPHostEnt( LDAPHostEnt *ldhp,
+	PRHostEnt *prhp );
+
+typedef struct ldapmsgwrapper {
+    LDAPMessage			*lmw_messagep;
+    struct ldapmsgwrapper	*lmw_next;
+} ldapmsgwrapper;
+
+
+#define CONNECTION_ERROR( lderr )	( (lderr) == LDAP_SERVER_DOWN || \
+					(lderr) == LDAP_CONNECT_ERROR )
+
+
+LDAP		*ld;
+PRUintn		tsdindex;
+#ifdef LDAP_MEMCACHE
+LDAPMemCache	*memcache = NULL;
+#define MEMCACHE_SIZE		(256*1024)	/* 256K bytes */
+#define MEMCACHE_TTL		(15*60)		/* 15 minutes */
+#endif
+
+
+main( int argc, char **argv )
+{
+	PRThread		*search_tid, *search_tid2, *search_tid3;
+	PRThread		*search_tid4, *modify_tid, *add_tid;
+	PRThread		*delete_tid;
+	struct ldap_thread_fns	tfns;
+	struct ldap_dns_fns	dnsfns;
+	int			rc;
+
+	if ( argc != 3 ) {
+		fprintf( stderr, "usage: %s host port\n", argv[0] );
+		exit( 1 );
+	}
+
+	PR_Init( PR_USER_THREAD, PR_PRIORITY_NORMAL, 0 );
+	if ( PR_NewThreadPrivateIndex( &tsdindex, NULL ) != PR_SUCCESS ) {
+		perror( "PR_NewThreadPrivateIndex" );
+		exit( 1 );
+	}
+	tsd_setup();	/* for main thread */
+
+	if ( (ld = ldap_init( argv[1], atoi( argv[2] ) )) == NULL ) {
+		perror( "ldap_open" );
+		exit( 1 );
+	}
+
+	/* set thread function pointers */
+	memset( &tfns, '\0', sizeof(struct ldap_thread_fns) );
+	tfns.ltf_mutex_alloc = my_mutex_alloc;
+	tfns.ltf_mutex_free = my_mutex_free;
+	tfns.ltf_mutex_lock = my_mutex_lock;
+	tfns.ltf_mutex_unlock = my_mutex_unlock;
+	tfns.ltf_get_errno = get_errno;
+	tfns.ltf_set_errno = set_errno;
+	tfns.ltf_get_lderrno = get_ld_error;
+	tfns.ltf_set_lderrno = set_ld_error;
+	tfns.ltf_lderrno_arg = NULL;
+	if ( ldap_set_option( ld, LDAP_OPT_THREAD_FN_PTRS, (void *) &tfns )
+	    != 0 ) {
+		ldap_perror( ld, "ldap_set_option: thread functions" );
+		exit( 1 );
+	}
+
+	/* set DNS function pointers */
+	memset( &dnsfns, '\0', sizeof(struct ldap_dns_fns) );
+	dnsfns.lddnsfn_bufsize = PR_NETDB_BUF_SIZE;
+	dnsfns.lddnsfn_gethostbyname = my_gethostbyname;
+	dnsfns.lddnsfn_gethostbyaddr = my_gethostbyaddr;
+	if ( ldap_set_option( ld, LDAP_OPT_DNS_FN_PTRS, (void *)&dnsfns )
+	    != 0 ) {
+		ldap_perror( ld, "ldap_set_option: DNS functions" );
+		exit( 1 );
+	}
+
+#ifdef LDAP_MEMCACHE
+	/* create the in-memory cache */
+	if (( rc = ldap_memcache_init( MEMCACHE_TTL, MEMCACHE_SIZE, NULL,
+	    &tfns, &memcache )) != LDAP_SUCCESS ) {
+		fprintf( stderr, "ldap_memcache_init failed - %s\n",
+		    ldap_err2string( rc ));
+		exit( 1 );
+	}
+	if (( rc = ldap_memcache_set( ld, memcache )) != LDAP_SUCCESS ) {
+		fprintf( stderr, "ldap_memcache_set failed - %s\n",
+		    ldap_err2string( rc ));
+		exit( 1 );
+	}
+#endif
+
+	/*
+	 * set option so that the next call to ldap_simple_bind_s() after
+	 * the server connection is lost will attempt to reconnect.
+	 */
+	if ( ldap_set_option( ld, LDAP_OPT_RECONNECT, LDAP_OPT_ON ) != 0 ) {
+		ldap_perror( ld, "ldap_set_option: reconnect" );
+		exit( 1 );
+	}
+
+	/* initial bind */
+	if ( simplebind( ld, "ldap_simple_bind_s/main", 1 ) != LDAP_SUCCESS ) {
+		exit( 1 );
+	}
+
+	/* create the operation threads */
+	if ( (search_tid = PR_CreateThread( PR_USER_THREAD, search_thread,
+	    "1", PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD,
+	    0 )) == NULL ) {
+		perror( "PR_CreateThread search_thread" );
+		exit( 1 );
+	}
+	if ( (modify_tid = PR_CreateThread( PR_USER_THREAD, modify_thread,
+	    "2", PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD,
+	    0 )) == NULL ) {
+		perror( "PR_CreateThread modify_thread" );
+		exit( 1 );
+	}
+	if ( (search_tid2 = PR_CreateThread( PR_USER_THREAD, search_thread,
+	    "3", PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD,
+	    0 )) == NULL ) {
+		perror( "PR_CreateThread search_thread 2" );
+		exit( 1 );
+	}
+	if ( (add_tid = PR_CreateThread( PR_USER_THREAD, add_thread,
+	    "4", PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD,
+	    0 )) == NULL ) {
+		perror( "PR_CreateThread add_thread" );
+		exit( 1 );
+	}
+	if ( (search_tid3 = PR_CreateThread( PR_USER_THREAD, search_thread,
+	    "5", PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD,
+	    0 )) == NULL ) {
+		perror( "PR_CreateThread search_thread 3" );
+		exit( 1 );
+	}
+	if ( (delete_tid = PR_CreateThread( PR_USER_THREAD, delete_thread,
+	    "6", PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD,
+	    0 )) == NULL ) {
+		perror( "PR_CreateThread delete_thread" );
+		exit( 1 );
+	}
+	if ( (search_tid4 = PR_CreateThread( PR_USER_THREAD, search_thread,
+	    "7", PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD,
+	    0 )) == NULL ) {
+		perror( "PR_CreateThread search_thread 4" );
+		exit( 1 );
+	}
+
+	PR_Cleanup();
+	return( 0 );
+}
+
+
+static int
+simplebind( LDAP *ld, char *msg, int tries )
+{
+	int	rc;
+
+	while ( tries-- > 0 ) {
+		rc = ldap_simple_bind_s( ld, NAME, PASSWORD );
+		if ( rc != LDAP_SUCCESS ) {
+			ldap_perror( ld, msg );
+		}
+		if ( tries == 0 || !CONNECTION_ERROR( rc )) {
+			return( rc );
+		}
+		fprintf( stderr,
+		    "%s: sleeping for 5 secs - will try %d more time(s)...\n",
+		    msg, tries );
+		sleep( 5 );
+	}
+
+	return( rc );
+}
+
+
+static void
+search_thread( void *arg1 )
+{
+	LDAPMessage	*res;
+	LDAPMessage	*e;
+	char		*a;
+	char		**v;
+	char		*dn;
+	BerElement	*ber;
+	int		i, rc, msgid;
+	void		*tsd;
+	char		*id = arg1;
+
+	printf( "search_thread\n" );
+	tsd_setup();
+	for ( ;; ) {
+		printf( "%sSearching...\n", id );
+		if ( (msgid = ldap_search( ld, BASE, LDAP_SCOPE_SUBTREE,
+		    "(objectclass=*)", NULL, 0 )) == -1 ) {
+			ldap_perror( ld, "ldap_search_s" );
+			rc =  ldap_get_lderrno( ld, NULL, NULL );
+			if ( CONNECTION_ERROR( rc ) && simplebind( ld,
+			    "bind-search_thread", 5 ) != LDAP_SUCCESS ) {
+				return;
+			}
+			continue;
+		}
+		while ( (rc = ldap_result( ld, msgid, 0, NULL, &res ))
+		    == LDAP_RES_SEARCH_ENTRY ) {
+			for ( e = ldap_first_entry( ld, res ); e != NULL;
+			    e = ldap_next_entry( ld, e ) ) {
+				dn = ldap_get_dn( ld, e );
+				/* printf( "%sdn: %s\n", id, dn ); */
+				free( dn );
+				for ( a = ldap_first_attribute( ld, e, &ber );
+				    a != NULL; a = ldap_next_attribute( ld, e,
+				    ber ) ) {
+					v = ldap_get_values( ld, e, a );
+					for ( i = 0; v && v[i] != 0; i++ ) {
+						/*
+						printf( "%s%s: %s\n", id, a,
+						    v[i] );
+						*/
+					}
+					ldap_value_free( v );
+					ldap_memfree( a );
+				}
+				if ( ber != NULL ) {
+					ber_free( ber, 0 );
+				}
+			}
+			ldap_msgfree( res );
+			/* printf( "%s\n", id ); */
+		}
+
+		if ( rc == -1 || ldap_result2error( ld, res, 0 ) !=
+		    LDAP_SUCCESS ) {
+			ldap_perror( ld, "ldap_search" );
+		} else {
+			printf( "%sDone with one round\n", id );
+		}
+
+		if ( rc == -1 ) {
+			rc = ldap_get_lderrno( ld, NULL, NULL );
+			if ( CONNECTION_ERROR( rc ) && simplebind( ld,
+			    "bind-search_thread", 5 ) != LDAP_SUCCESS ) {
+				return;
+			}
+		}
+	}
+}
+
+static void
+modify_thread( void *arg1 )
+{
+	LDAPMessage	*res;
+	LDAPMessage	*e;
+	int		i, modentry, entries, msgid, rc;
+	LDAPMod		mod;
+	LDAPMod		*mods[2];
+	char		*vals[2];
+	char		*dn;
+	char		*id = arg1;
+	ldapmsgwrapper	*list, *lmwp, *lastlmwp;
+
+	printf( "modify_thread\n" );
+	tsd_setup();
+	if ( (msgid = ldap_search( ld, BASE, LDAP_SCOPE_SUBTREE,
+	    "(objectclass=*)", NULL, 0 )) == -1 ) {
+		ldap_perror( ld, "ldap_search_s" );
+		exit( 1 );
+	}
+	entries = 0;
+	list = lastlmwp = NULL;
+	while ( (rc = ldap_result( ld, msgid, 0, NULL, &res ))
+	    == LDAP_RES_SEARCH_ENTRY ) {
+		entries++;
+		if (( lmwp = (ldapmsgwrapper *)
+			malloc( sizeof( ldapmsgwrapper ))) == NULL ) {
+			perror( "modify_thread: malloc" );
+			exit( 1 );
+		}
+		lmwp->lmw_messagep = res;
+		lmwp->lmw_next = NULL;
+		if ( lastlmwp == NULL ) {
+			list = lastlmwp = lmwp;
+		} else {
+			lastlmwp->lmw_next = lmwp;
+		}
+		lastlmwp = lmwp;
+	}
+	if ( rc == -1 || ldap_result2error( ld, res, 0 ) != LDAP_SUCCESS ) {
+		ldap_perror( ld, "modify_thread: ldap_search" );
+		exit( 1 );
+	} else {
+		entries++;
+		printf( "%sModify got %d entries\n", id, entries );
+	}
+
+	mods[0] = &mod;
+	mods[1] = NULL;
+	vals[0] = "bar";
+	vals[1] = NULL;
+	for ( ;; ) {
+		modentry = rand() % entries;
+		for ( i = 0, lmwp = list; lmwp != NULL && i < modentry;
+		    i++, lmwp = lmwp->lmw_next ) {
+			/* NULL */
+		}
+
+		if ( lmwp == NULL ) {
+			fprintf( stderr,
+			    "%sModify could not find entry %d of %d\n",
+			    id, modentry, entries );
+			continue;
+		}
+		e = lmwp->lmw_messagep;
+		printf( "%sPicked entry %d of %d\n", id, i, entries );
+		dn = ldap_get_dn( ld, e );
+		mod.mod_op = LDAP_MOD_REPLACE;
+		mod.mod_type = "description";
+		mod.mod_values = vals;
+		printf( "%sModifying (%s)\n", id, dn );
+		if (( rc = ldap_modify_s( ld, dn, mods )) != LDAP_SUCCESS ) {
+			ldap_perror( ld, "ldap_modify_s" );
+			if ( CONNECTION_ERROR( rc ) && simplebind( ld,
+			    "bind-modify_thread", 5 ) != LDAP_SUCCESS ) {
+				return;
+			}
+		}
+		free( dn );
+	}
+}
+
+static void
+add_thread( void *arg1 )
+{
+	LDAPMod	mod[5];
+	LDAPMod	*mods[6];
+	char	dn[BUFSIZ], name[40];
+	char	*cnvals[2], *snvals[2], *ocvals[2];
+	int	i, rc;
+	char	*id = arg1;
+
+	printf( "add_thread\n" );
+	tsd_setup();
+	for ( i = 0; i < 5; i++ ) {
+		mods[i] = &mod[i];
+	}
+	mods[5] = NULL;
+	mod[0].mod_op = 0;
+	mod[0].mod_type = "cn";
+	mod[0].mod_values = cnvals;
+	cnvals[1] = NULL;
+	mod[1].mod_op = 0;
+	mod[1].mod_type = "sn";
+	mod[1].mod_values = snvals;
+	snvals[1] = NULL;
+	mod[2].mod_op = 0;
+	mod[2].mod_type = "objectclass";
+	mod[2].mod_values = ocvals;
+	ocvals[0] = "person";
+	ocvals[1] = NULL;
+	mods[3] = NULL;
+
+	for ( ;; ) {
+		sprintf( name, "%d", rand() );
+		sprintf( dn, "cn=%s, " BASE, name );
+		cnvals[0] = name;
+		snvals[0] = name;
+
+		printf( "%sAdding entry (%s)\n", id, dn );
+		if (( rc = ldap_add_s( ld, dn, mods )) != LDAP_SUCCESS ) {
+			ldap_perror( ld, "ldap_add_s" );
+			if ( CONNECTION_ERROR( rc ) && simplebind( ld,
+			    "bind-add_thread", 5 ) != LDAP_SUCCESS ) {
+				return;
+			}
+		}
+	}
+}
+
+static void
+delete_thread( void *arg1 )
+{
+	LDAPMessage	*res;
+	char		dn[BUFSIZ], name[40];
+	int		entries, msgid, rc;
+	char		*id = arg1;
+
+	printf( "delete_thread\n" );
+	tsd_setup();
+	if ( (msgid = ldap_search( ld, BASE, LDAP_SCOPE_SUBTREE,
+	    "(objectclass=*)", NULL, 0 )) == -1 ) {
+		ldap_perror( ld, "delete_thread: ldap_search_s" );
+		exit( 1 );
+	}
+	entries = 0;
+	while ( (rc = ldap_result( ld, msgid, 0, NULL, &res ))
+	    == LDAP_RES_SEARCH_ENTRY ) {
+		entries++;
+		ldap_msgfree( res );
+	}
+	entries++;
+	if ( rc == -1 || ldap_result2error( ld, res, 1 ) != LDAP_SUCCESS ) {
+		ldap_perror( ld, "delete_thread: ldap_search" );
+	} else {
+		printf( "%sDelete got %d entries\n", id, entries );
+	}
+
+	for ( ;; ) {
+		sprintf( name, "%d", rand() );
+		sprintf( dn, "cn=%s, " BASE, name );
+
+		printf( "%sDeleting entry (%s)\n", id, dn );
+		if (( rc = ldap_delete_s( ld, dn )) != LDAP_SUCCESS ) {
+			ldap_perror( ld, "ldap_delete_s" );
+			if ( CONNECTION_ERROR( rc ) && simplebind( ld,
+			    "bind-delete_thread", 5 ) != LDAP_SUCCESS ) {
+				return;
+			}
+		}
+	}
+}
+
+struct ldap_error {
+	int	le_errno;
+	char	*le_matched;
+	char	*le_errmsg;
+};
+
+static void
+tsd_setup()
+{
+	void	*tsd;
+
+	tsd = (void *) PR_GetThreadPrivate( tsdindex );
+	if ( tsd != NULL ) {
+		fprintf( stderr, "tsd non-null!\n" );
+		exit( 1 );
+	}
+	tsd = (void *) calloc( 1, sizeof(struct ldap_error) );
+	if ( PR_SetThreadPrivate( tsdindex, tsd ) != 0 ) {
+		perror( "PR_SetThreadPrivate" );
+		exit( 1 );
+	}
+}
+
+static void
+set_ld_error( int err, char *matched, char *errmsg, void *dummy )
+{
+	struct ldap_error *le;
+
+	le = (void *) PR_GetThreadPrivate( tsdindex );
+	le->le_errno = err;
+	if ( le->le_matched != NULL ) {
+		ldap_memfree( le->le_matched );
+	}
+	le->le_matched = matched;
+	if ( le->le_errmsg != NULL ) {
+		ldap_memfree( le->le_errmsg );
+	}
+	le->le_errmsg = errmsg;
+}
+
+static int
+get_ld_error( char **matchedp, char **errmsgp, void *dummy )
+{
+	struct ldap_error *le;
+
+	le = PR_GetThreadPrivate( tsdindex );
+	if ( matchedp != NULL ) {
+		*matchedp = le->le_matched;
+	}
+	if ( errmsgp != NULL ) {
+		*errmsgp = le->le_errmsg;
+	}
+	return( le->le_errno );
+}
+
+static void
+set_errno( int oserrno )
+{
+	/* XXXmcs: should this be PR_SetError( oserrno, 0 )? */
+	PR_SetError( PR_UNKNOWN_ERROR, oserrno );
+}
+
+static int
+get_errno( void )
+{
+	/* XXXmcs: should this be PR_GetError()? */
+	return( PR_GetOSError());
+}
+
+static void *
+my_mutex_alloc( void )
+{
+	return( (void *)PR_NewLock());
+}
+
+static void
+my_mutex_free( void *mutex )
+{
+	PR_DestroyLock( (PRLock *)mutex );
+}
+
+static int
+my_mutex_lock( void *mutex )
+{
+	PR_Lock( (PRLock *)mutex );
+	return( 0 );
+}
+
+static int
+my_mutex_unlock( void *mutex )
+{
+	if ( PR_Unlock( (PRLock *)mutex ) == PR_FAILURE ) {
+		return( -1 );
+	}
+
+	return( 0 );
+}
+
+static LDAPHostEnt *
+my_gethostbyname( const char *name, LDAPHostEnt *result,
+	char *buffer, int buflen, int *statusp, void *extradata )
+{
+	PRHostEnt	prhent;
+
+	if ( PR_GetHostByName( name, buffer, buflen,
+	    &prhent ) != PR_SUCCESS ) {
+		return( NULL );
+	}
+
+	return( copyPRHostEnt2LDAPHostEnt( result, &prhent ));
+}
+
+static LDAPHostEnt *
+my_gethostbyaddr( const char *addr, int length, int type, LDAPHostEnt *result,
+	char *buffer, int buflen, int *statusp, void *extradata )
+{
+	PRHostEnt	prhent;
+
+	if ( PR_GetHostByAddr( (PRNetAddr *)addr, buffer, buflen,
+	    &prhent ) != PR_SUCCESS ) {
+		return( NULL );
+	}
+
+	return( copyPRHostEnt2LDAPHostEnt( result, &prhent ));
+}
+
+static LDAPHostEnt *
+copyPRHostEnt2LDAPHostEnt( LDAPHostEnt *ldhp, PRHostEnt *prhp )
+{
+	ldhp->ldaphe_name = prhp->h_name;
+	ldhp->ldaphe_aliases = prhp->h_aliases;
+	ldhp->ldaphe_addrtype = prhp->h_addrtype;
+	ldhp->ldaphe_length =  prhp->h_length;
+	ldhp->ldaphe_addr_list =  prhp->h_addr_list;
+	return( ldhp );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/open.c
@@ -0,0 +1,912 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ *  Copyright (c) 1995 Regents of the University of Michigan.
+ *  All rights reserved.
+ */
+/*
+ *  open.c
+ */
+
+#if 0
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1995 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+#ifdef LDAP_SASLIO_HOOKS
+/* Valid for any ANSI C compiler */
+#include <limits.h>
+extern sasl_callback_t client_callbacks[];
+#endif
+
+#define VI_PRODUCTVERSION 3
+
+#ifndef INADDR_LOOPBACK
+#define INADDR_LOOPBACK	((unsigned long) 0x7f000001)
+#endif
+
+#ifdef LDAP_DEBUG
+int	ldap_debug = 0;
+#endif
+
+#ifdef _WINDOWS
+#define USE_WINDOWS_TLS /* thread local storage */
+#endif
+
+/*
+ * global defaults for callbacks are stored here.  callers of the API set
+ *    these by passing a NULL "ld" to ldap_set_option().  Everything in
+ *    nsldapi_ld_defaults can be overridden on a per-ld basis as well (the
+ *    memory allocation functions are global to all ld's).
+ */
+struct ldap                     nsldapi_ld_defaults;
+struct ldap_memalloc_fns        nsldapi_memalloc_fns = { 0, 0, 0, 0 };
+int				nsldapi_initialized = 0;
+
+#ifdef USE_PTHREADS
+#include <pthread.h>
+#ifdef VMS
+/*
+** pthread_self() is not a routine on OpenVMS; it's inline assembler code. 
+** Since we need a real address which we can stuff away into a table, we need 
+** to make sure that pthread_self maps to the real pthread_self routine (yes,
+** we do have one fortunately).
+*/
+#undef pthread_self
+#define pthread_self PTHREAD_SELF
+extern pthread_t pthread_self (void);
+#endif
+static pthread_key_t		nsldapi_key;
+static pthread_mutex_t		nsldapi_init_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+struct nsldapi_ldap_error {
+        int     le_errno;
+        char    *le_matched;
+        char    *le_errmsg;
+};
+#elif defined (USE_WINDOWS_TLS)
+static DWORD dwTlsIndex;
+struct nsldapi_ldap_error {
+	int	le_errno;
+	char	*le_matched;
+	char	*le_errmsg;
+};
+#elif defined (_WINDOWS) /* use static tls */
+__declspec ( thread ) int	nsldapi_gldaperrno;
+__declspec ( thread ) char	*nsldapi_gmatched = NULL;
+__declspec ( thread ) char	*nsldapi_gldaperror = NULL; 
+#endif /* USE_WINDOWS_TLS */
+
+
+#ifdef _WINDOWS
+#define	LDAP_MUTEX_T	HANDLE
+static LDAP_MUTEX_T		nsldapi_init_mutex;
+
+int
+pthread_mutex_init( LDAP_MUTEX_T *mp, void *attr)
+{
+        if ( (*mp = CreateMutex(NULL, FALSE, NULL)) == NULL )
+                return( 1 );
+        else
+                return( 0 );
+}
+
+static void *
+pthread_mutex_alloc( void )
+{
+        LDAP_MUTEX_T *mutexp;
+
+        if ( (mutexp = malloc( sizeof(LDAP_MUTEX_T) )) != NULL ) {
+                pthread_mutex_init( mutexp, NULL );
+        }
+        return( mutexp );
+}
+
+int
+pthread_mutex_destroy( LDAP_MUTEX_T *mp )
+{
+        if ( !(CloseHandle(*mp)) )
+                return( 1 );
+        else
+                return( 0 );
+}
+
+static void
+pthread_mutex_free( void *mutexp )
+{
+        pthread_mutex_destroy( (LDAP_MUTEX_T *) mutexp );
+        free( mutexp );
+}
+
+int
+pthread_mutex_lock( LDAP_MUTEX_T *mp )
+{
+        if ( (WaitForSingleObject(*mp, INFINITE) != WAIT_OBJECT_0) )
+                return( 1 );
+        else
+                return( 0 );
+}
+
+int
+pthread_mutex_unlock( LDAP_MUTEX_T *mp )
+{
+        if ( !(ReleaseMutex(*mp)) )
+                return( 1 );
+        else
+                return( 0 );
+}
+
+static int
+get_errno( void )
+{
+	return errno;
+}
+
+static void
+set_errno( int Errno )
+{
+	errno = Errno;
+}
+
+#ifdef USE_WINDOWS_TLS
+static void
+set_ld_error( int err, char *matched, char *errmsg, void *dummy )
+{
+	struct nsldapi_ldap_error *le;
+	void *tsd;
+
+	le = TlsGetValue( dwTlsIndex );
+
+	if (le == NULL) {
+		tsd = (void *)calloc(1, sizeof(struct nsldapi_ldap_error));
+		TlsSetValue( dwTlsIndex, tsd );
+	}
+
+	le = TlsGetValue ( dwTlsIndex );
+
+	if (le == NULL)
+		return;
+
+	le->le_errno = err;
+
+	if ( le->le_matched != NULL ) {
+		ldap_memfree( le->le_matched );
+	}
+	le->le_matched = matched;
+
+	if ( le->le_errmsg != NULL ) {
+		ldap_memfree( le->le_errmsg );
+	}
+	le->le_errmsg = errmsg;
+}
+
+static int
+get_ld_error ( char **matched, char **errmsg, void *dummy )
+{
+	struct nsldapi_ldap_error *le;
+
+	le = TlsGetValue( dwTlsIndex );
+	if ( matched != NULL ) {
+		*matched = le->le_matched;
+	}
+
+	if ( errmsg != NULL ) {
+		*errmsg = le->le_errmsg;
+	}
+
+	return( le->le_errno );
+}
+#else
+static int
+get_ld_error( char **LDMatched, char **LDError, void * Args )
+{
+	if ( LDMatched != NULL )
+	{
+		*LDMatched = nsldapi_gmatched;
+	}
+	if ( LDError != NULL )
+	{
+		*LDError = nsldapi_gldaperror;
+	}
+	return nsldapi_gldaperrno;
+}
+
+static void
+set_ld_error( int LDErrno, char *  LDMatched, char *  LDError,
+	void *  Args )
+{
+	/* Clean up any previous string storage. */
+	if ( nsldapi_gmatched != NULL )
+	{
+		ldap_memfree( nsldapi_gmatched );
+	}
+	if ( nsldapi_gldaperror != NULL )
+	{
+		ldap_memfree( nsldapi_gldaperror );
+	}
+
+	nsldapi_gldaperrno  = LDErrno;
+	nsldapi_gmatched    = LDMatched;
+	nsldapi_gldaperror  = LDError;
+}
+#endif /* USE_WINDOWS_TLS */
+#endif /* ! _WINDOWS */
+
+#ifdef USE_PTHREADS
+static void *
+pthread_mutex_alloc( void )
+{
+	pthread_mutex_t *mutexp;
+
+	if ( (mutexp = malloc( sizeof(pthread_mutex_t) )) != NULL ) {
+		pthread_mutex_init( mutexp, NULL );
+	}
+	return( mutexp );
+}
+
+static void
+pthread_mutex_free( void *mutexp )
+{
+	pthread_mutex_destroy( (pthread_mutex_t *) mutexp );
+	free( mutexp );
+}
+
+static void
+set_ld_error( int err, char *matched, char *errmsg, void *dummy )
+{
+        struct nsldapi_ldap_error *le;
+        void *tsd;
+
+        le = pthread_getspecific( nsldapi_key );
+
+        if (le == NULL) {
+                tsd = (void *)calloc(1, sizeof(struct nsldapi_ldap_error));
+                pthread_setspecific( nsldapi_key, tsd );
+        }
+
+        le = pthread_getspecific( nsldapi_key );
+
+        if (le == NULL)
+                return;
+
+        le->le_errno = err;
+
+        if ( le->le_matched != NULL ) {
+                ldap_memfree( le->le_matched );
+        }
+        le->le_matched = matched;
+
+        if ( le->le_errmsg != NULL ) {
+                ldap_memfree( le->le_errmsg );
+        }
+        le->le_errmsg = errmsg;
+}
+
+static int
+get_ld_error( char **matched, char **errmsg, void *dummy )
+{
+        struct nsldapi_ldap_error *le;
+
+        le = pthread_getspecific( nsldapi_key );
+
+        if (le == NULL)
+                return( LDAP_SUCCESS );
+
+        if ( matched != NULL ) {
+                *matched = le->le_matched;
+        }
+        if ( errmsg != NULL ) {
+                *errmsg = le->le_errmsg;
+        }
+        return( le->le_errno );
+}
+
+static void
+set_errno( int err )
+{
+        errno = err;
+}
+
+static int
+get_errno( void )
+{
+        return( errno );
+}
+#endif /* use_pthreads */
+
+#if defined(USE_PTHREADS) || defined(_WINDOWS)
+static struct ldap_thread_fns
+	nsldapi_default_thread_fns = {
+		(void *(*)(void))pthread_mutex_alloc,
+		(void (*)(void *))pthread_mutex_free,
+		(int (*)(void *))pthread_mutex_lock,
+		(int (*)(void *))pthread_mutex_unlock,
+                (int (*)(void))get_errno,
+                (void (*)(int))set_errno,
+                (int (*)(char **, char **, void *))get_ld_error,
+                (void (*)(int, char *, char *, void *))set_ld_error,
+		0 };
+
+static struct ldap_extra_thread_fns
+	nsldapi_default_extra_thread_fns = {
+		0, 0, 0, 0, 0,
+#ifdef _WINDOWS
+		0
+#else
+		(void *(*)(void))pthread_self
+#endif /* _WINDOWS */
+		};
+#endif /* use_pthreads || _windows */
+
+void
+nsldapi_initialize_defaults( void )
+{
+#ifdef _WINDOWS
+	pthread_mutex_init( &nsldapi_init_mutex, NULL );
+#endif /* _WINDOWS */
+
+#if defined(USE_PTHREADS) || defined(_WINDOWS)
+	pthread_mutex_lock( &nsldapi_init_mutex );
+
+	if ( nsldapi_initialized ) {
+		pthread_mutex_unlock( &nsldapi_init_mutex );
+		return;
+	}
+#else
+         if ( nsldapi_initialized ) {
+                 return;
+         }
+#endif /* use_pthreads || _windows */
+
+#ifdef USE_PTHREADS
+        if ( pthread_key_create(&nsldapi_key, free ) != 0) {
+                perror("pthread_key_create");
+        }
+#elif defined(USE_WINDOWS_TLS)
+	dwTlsIndex = TlsAlloc();
+#endif /* USE_WINDOWS_TLS */
+
+	memset( &nsldapi_memalloc_fns, 0, sizeof( nsldapi_memalloc_fns ));
+	memset( &nsldapi_ld_defaults, 0, sizeof( nsldapi_ld_defaults ));
+	nsldapi_ld_defaults.ld_options = LDAP_BITOPT_REFERRALS;
+	nsldapi_ld_defaults.ld_version = LDAP_VERSION3;
+	nsldapi_ld_defaults.ld_lberoptions = LBER_OPT_USE_DER;
+	nsldapi_ld_defaults.ld_refhoplimit = LDAP_DEFAULT_REFHOPLIMIT;
+
+#ifdef LDAP_SASLIO_HOOKS
+	/* SASL default option settings */
+	nsldapi_ld_defaults.ld_def_sasl_mech = NULL;
+	nsldapi_ld_defaults.ld_def_sasl_realm = NULL;
+	nsldapi_ld_defaults.ld_def_sasl_authcid = NULL;
+	nsldapi_ld_defaults.ld_def_sasl_authzid = NULL;
+	/* SASL Security properties */
+	nsldapi_ld_defaults.ld_sasl_secprops.max_ssf = UINT_MAX;
+	nsldapi_ld_defaults.ld_sasl_secprops.maxbufsize = SASL_MAX_BUFF_SIZE;
+	nsldapi_ld_defaults.ld_sasl_secprops.security_flags =
+		SASL_SEC_NOPLAINTEXT | SASL_SEC_NOANONYMOUS;
+
+	/* SASL mutex function callbacks */
+	sasl_set_mutex(
+		(sasl_mutex_alloc_t *)nsldapi_default_thread_fns.ltf_mutex_alloc,
+		(sasl_mutex_lock_t *)nsldapi_default_thread_fns.ltf_mutex_lock,
+		(sasl_mutex_unlock_t *)nsldapi_default_thread_fns.ltf_mutex_unlock,
+		(sasl_mutex_free_t *)nsldapi_default_thread_fns.ltf_mutex_free );
+
+	/* SASL memory allocation function callbacks */
+	sasl_set_alloc(
+		(sasl_malloc_t *)ldap_x_malloc,
+		(sasl_calloc_t *)ldap_x_calloc,
+		(sasl_realloc_t *)ldap_x_realloc,
+		(sasl_free_t *)ldap_x_free );
+
+	/* SASL library initialization */
+	if ( sasl_client_init( client_callbacks ) != SASL_OK ) {
+		nsldapi_initialized = 0;
+		pthread_mutex_unlock( &nsldapi_init_mutex );
+		return;
+	}
+#endif
+
+#if defined( STR_TRANSLATION ) && defined( LDAP_DEFAULT_CHARSET )
+	nsldapi_ld_defaults.ld_lberoptions |= LBER_OPT_TRANSLATE_STRINGS;
+#if LDAP_CHARSET_8859 == LDAP_DEFAULT_CHARSET
+	ldap_set_string_translators( &nsldapi_ld_defaults, ldap_8859_to_t61,
+	    ldap_t61_to_8859 );
+#endif /* LDAP_CHARSET_8859 == LDAP_DEFAULT_CHARSET */
+#endif /* STR_TRANSLATION && LDAP_DEFAULT_CHARSET */
+
+        /* set default connect timeout (in milliseconds) */
+        /* this was picked as it is the standard tcp timeout as well */
+        nsldapi_ld_defaults.ld_connect_timeout = LDAP_X_IO_TIMEOUT_NO_TIMEOUT;
+
+#if defined(USE_PTHREADS) || defined(_WINDOWS)
+        /* load up default platform specific locking routines */
+        if (ldap_set_option( &nsldapi_ld_defaults, LDAP_OPT_THREAD_FN_PTRS,
+                (void *)&nsldapi_default_thread_fns) != LDAP_SUCCESS) {
+		nsldapi_initialized = 0;
+		pthread_mutex_unlock( &nsldapi_init_mutex );
+                return;
+        }
+
+#ifndef _WINDOWS
+        /* load up default threadid function */
+        if (ldap_set_option( &nsldapi_ld_defaults, LDAP_OPT_EXTRA_THREAD_FN_PTRS,
+                (void *)&nsldapi_default_extra_thread_fns) != LDAP_SUCCESS) {
+		nsldapi_initialized = 0;
+		pthread_mutex_unlock( &nsldapi_init_mutex );
+                return;
+        }
+#endif /* _WINDOWS */
+	nsldapi_initialized = 1;
+	pthread_mutex_unlock( &nsldapi_init_mutex );
+#else
+        nsldapi_initialized = 1;
+#endif /* use_pthreads || _windows */
+}
+
+
+/*
+ * ldap_version - report version levels for important properties
+ * This function is deprecated.  Use ldap_get_option( ..., LDAP_OPT_API_INFO,
+ *	... ) instead.
+ *
+ * Example:
+ *	LDAPVersion ver;
+ *	ldap_version( &ver );
+ *  if ( (ver.sdk_version < 100) || (ver.SSL_version < 300) )
+ *      fprintf( stderr, "LDAP SDK level insufficient\n" );
+ *
+ * or:
+ *  if ( ldap_version(NULL) < 100 )
+ *      fprintf( stderr, "LDAP SDK level insufficient\n" );
+ *
+ */
+
+int
+LDAP_CALL
+ldap_version( LDAPVersion *ver )
+{
+	if ( NULL != ver )
+	{
+		memset( ver, 0, sizeof(*ver) );
+		ver->sdk_version = (int)(VI_PRODUCTVERSION * 100);
+		ver->protocol_version = LDAP_VERSION_MAX * 100;
+		ver->SSL_version = SSL_VERSION * 100;
+		/* 
+		 * set security to none by default 
+		 */
+
+		ver->security_level = LDAP_SECURITY_NONE;
+#if defined(LINK_SSL)
+#if defined(NS_DOMESTIC)
+		ver->security_level = 128;
+#elif defined(NSS_EXPORT)
+		ver->security_level = 40;
+#endif
+#endif
+
+	}
+	return (int)(VI_PRODUCTVERSION * 100);
+}
+
+/*
+ * ldap_open - initialize and connect to an ldap server.  A magic cookie to
+ * be used for future communication is returned on success, NULL on failure.
+ * "host" may be a space-separated list of hosts or IP addresses
+ *
+ * Example:
+ *	LDAP	*ld;
+ *	ld = ldap_open( hostname, port );
+ */
+
+LDAP *
+LDAP_CALL
+ldap_open( const char *host, int port )
+{
+	LDAP	*ld;
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_open\n", 0, 0, 0 );
+
+	if (( ld = ldap_init( host, port )) == NULL ) {
+		return( NULL );
+	}
+
+	LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK );
+	if ( nsldapi_open_ldap_defconn( ld ) < 0 ) {
+		LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
+		ldap_ld_free( ld, NULL, NULL, 0 );
+		return( NULL );
+	}
+
+	LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_open successful, ld_host is %s\n",
+		( ld->ld_host == NULL ) ? "(null)" : ld->ld_host, 0, 0 );
+
+	return( ld );
+}
+
+
+/*
+ * ldap_init - initialize the LDAP library.  A magic cookie to be used for
+ * future communication is returned on success, NULL on failure.
+ * "defhost" may be a space-separated list of hosts or IP addresses
+ *
+ * NOTE: If you want to use IPv6, you must use prldap creating a LDAP handle
+ * with prldap_init instead of ldap_init. Or install the NSPR functions
+ * by calling prldap_install_routines. (See the nspr samples in examples)
+ *
+ * Example:
+ *	LDAP	*ld;
+ *	ld = ldap_init( default_hostname, default_port );
+ */
+LDAP *
+LDAP_CALL
+ldap_init( const char *defhost, int defport )
+{
+	LDAP	*ld;
+
+	if ( !nsldapi_initialized ) {
+		nsldapi_initialize_defaults();
+	}
+
+	if ( defport < 0 || defport > LDAP_PORT_MAX ) {
+	    LDAPDebug( LDAP_DEBUG_ANY,
+		    "ldap_init: port %d is invalid (port numbers must range from 1 to %d)\n",
+		    defport, LDAP_PORT_MAX, 0 );
+#if !defined( macintosh ) && !defined( DOS ) && !defined( BEOS )
+	    errno = EINVAL;
+#endif
+	    return( NULL );
+	}
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_init\n", 0, 0, 0 );
+
+	if ( (ld = (LDAP*)NSLDAPI_MALLOC( sizeof(struct ldap) )) == NULL ) {
+		return( NULL );
+	}
+
+	/* copy defaults */
+	SAFEMEMCPY( ld, &nsldapi_ld_defaults, sizeof( struct ldap ));
+	if ( nsldapi_ld_defaults.ld_io_fns_ptr != NULL ) {
+		if (( ld->ld_io_fns_ptr = (struct ldap_io_fns *)NSLDAPI_MALLOC(
+		    sizeof( struct ldap_io_fns ))) == NULL ) {
+			NSLDAPI_FREE( (char *)ld );
+			return( NULL );
+		}
+		/* struct copy */
+		*(ld->ld_io_fns_ptr) = *(nsldapi_ld_defaults.ld_io_fns_ptr);
+	}
+
+	/* call the new handle I/O callback if one is defined */
+	if ( ld->ld_extnewhandle_fn != NULL ) {
+		/*
+		 * We always pass the session extended I/O argument to
+		 * the new handle callback.
+		 */
+		if ( ld->ld_extnewhandle_fn( ld, ld->ld_ext_session_arg )
+		    != LDAP_SUCCESS ) {
+			NSLDAPI_FREE( (char*)ld );
+			return( NULL );
+		}
+	}
+
+	/* allocate session-specific resources */
+	if (( ld->ld_sbp = ber_sockbuf_alloc()) == NULL ||
+	    ( defhost != NULL &&
+	    ( ld->ld_defhost = nsldapi_strdup( defhost )) == NULL ) ||
+	    ((ld->ld_mutex = (void **) NSLDAPI_CALLOC( LDAP_MAX_LOCK, sizeof(void *))) == NULL )) {
+		if ( ld->ld_sbp != NULL ) {
+			ber_sockbuf_free( ld->ld_sbp );
+		}
+		if( ld->ld_mutex != NULL ) {
+			NSLDAPI_FREE( ld->ld_mutex );
+		}
+		NSLDAPI_FREE( (char*)ld );
+		return( NULL );
+	}
+
+	/* install Sockbuf I/O functions if set in LDAP * */
+	if ( ld->ld_extread_fn != NULL || ld->ld_extwrite_fn != NULL ) {
+		struct lber_x_ext_io_fns lberiofns;
+
+		memset( &lberiofns, 0, sizeof( lberiofns ));
+
+		lberiofns.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE;
+		lberiofns.lbextiofn_read = ld->ld_extread_fn;
+		lberiofns.lbextiofn_write = ld->ld_extwrite_fn;
+		lberiofns.lbextiofn_writev = ld->ld_extwritev_fn;
+		lberiofns.lbextiofn_socket_arg = NULL;
+		ber_sockbuf_set_option( ld->ld_sbp, LBER_SOCKBUF_OPT_EXT_IO_FNS,
+			(void *)&lberiofns );
+	}
+
+	/* allocate mutexes */
+	nsldapi_mutex_alloc_all( ld );
+
+	/* set default port */
+	ld->ld_defport = ( defport == 0 ) ? LDAP_PORT : defport;
+
+	return( ld );
+}
+
+
+void
+nsldapi_mutex_alloc_all( LDAP *ld )
+{
+	int	i;
+
+	if ( ld != &nsldapi_ld_defaults && ld->ld_mutex != NULL ) {
+		for ( i = 0; i<LDAP_MAX_LOCK; i++ ) {
+			ld->ld_mutex[i] = LDAP_MUTEX_ALLOC( ld );
+			ld->ld_mutex_threadid[i] = (void *) -1; 
+			ld->ld_mutex_refcnt[i] = 0; 
+		}
+	} 
+}
+
+
+void
+nsldapi_mutex_free_all( LDAP *ld )
+{
+	int	i;
+
+	if ( ld != &nsldapi_ld_defaults && ld->ld_mutex != NULL ) {
+		for ( i = 0; i<LDAP_MAX_LOCK; i++ ) {
+			LDAP_MUTEX_FREE( ld, ld->ld_mutex[i] );
+		}
+	}
+}
+
+
+/* returns 0 if connection opened and -1 if an error occurs */
+int
+nsldapi_open_ldap_defconn( LDAP *ld )
+{
+	LDAPServer	*srv;
+
+	if (( srv = (LDAPServer *)NSLDAPI_CALLOC( 1, sizeof( LDAPServer ))) ==
+	    NULL || ( ld->ld_defhost != NULL && ( srv->lsrv_host =
+	    nsldapi_strdup( ld->ld_defhost )) == NULL )) {
+		LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+		return( -1 );
+	}
+	srv->lsrv_port = ld->ld_defport;
+
+	if (( ld->ld_options & LDAP_BITOPT_SSL ) != 0 ) {
+		srv->lsrv_options |= LDAP_SRV_OPT_SECURE;
+	}
+
+	if (( ld->ld_defconn = nsldapi_new_connection( ld, &srv, 1, 1, 0 ))
+	    == NULL ) {
+		if ( ld->ld_defhost != NULL ) {
+			NSLDAPI_FREE( srv->lsrv_host );
+		}
+		NSLDAPI_FREE( (char *)srv );
+		return( -1 );
+	}
+	++ld->ld_defconn->lconn_refcnt;	/* so it never gets closed/freed */
+
+	return( 0 );
+}
+
+
+struct ldap_x_hostlist_status {
+	char	*lhs_hostlist;
+	char	*lhs_nexthost;
+	int	lhs_defport;
+};
+
+/*
+ * Return the first host and port in hostlist (setting *hostp and *portp).
+ * Return value is an LDAP API error code (LDAP_SUCCESS if all goes well).
+ * Note that a NULL or zero-length hostlist causes the host "127.0.0.1" to
+ * be returned.
+ */
+int LDAP_CALL
+ldap_x_hostlist_first( const char *hostlist, int defport, char **hostp,
+    int *portp, struct ldap_x_hostlist_status **statusp )
+{
+
+	if ( NULL == hostp || NULL == portp || NULL == statusp ) {
+		return( LDAP_PARAM_ERROR );
+	}
+
+	if ( NULL == hostlist || *hostlist == '\0' ) {
+		*hostp = nsldapi_strdup( "127.0.0.1" );
+		if ( NULL == *hostp ) {
+			return( LDAP_NO_MEMORY );
+		}
+		*portp = defport;
+		*statusp = NULL;
+		return( LDAP_SUCCESS );
+	}
+
+	*statusp = NSLDAPI_CALLOC( 1, sizeof( struct ldap_x_hostlist_status ));
+	if ( NULL == *statusp ) {
+		return( LDAP_NO_MEMORY );
+	}
+	(*statusp)->lhs_hostlist = nsldapi_strdup( hostlist );
+	if ( NULL == (*statusp)->lhs_hostlist ) {
+		return( LDAP_NO_MEMORY );
+	}
+	(*statusp)->lhs_nexthost = (*statusp)->lhs_hostlist;
+	(*statusp)->lhs_defport = defport;
+	return( ldap_x_hostlist_next( hostp, portp, *statusp ));
+}
+
+/*
+ * Return the next host and port in hostlist (setting *hostp and *portp).
+ * Return value is an LDAP API error code (LDAP_SUCCESS if all goes well).
+ * If no more hosts are available, LDAP_SUCCESS is returned but *hostp is set
+ * to NULL.
+ */
+int LDAP_CALL
+ldap_x_hostlist_next( char **hostp, int *portp,
+	struct ldap_x_hostlist_status *status )
+{
+	char	*q;
+	int		squarebrackets = 0;
+
+	if ( NULL == hostp || NULL == portp ) {
+		return( LDAP_PARAM_ERROR );
+	}
+
+	if ( NULL == status || NULL == status->lhs_nexthost ) {
+		*hostp = NULL;
+		return( LDAP_SUCCESS );
+	}
+
+	/*
+	 * skip past leading '[' if present (IPv6 addresses may be surrounded
+	 * with square brackets, e.g., [fe80::a00:20ff:fee5:c0b4]:389
+	 */
+	if ( status->lhs_nexthost[0] == '[' ) {
+		++status->lhs_nexthost;
+		squarebrackets = 1;
+	}
+
+	/* copy host into *hostp */
+	if ( NULL != ( q = strchr( status->lhs_nexthost, ' ' ))) {
+		size_t	len = q - status->lhs_nexthost;
+		*hostp = NSLDAPI_MALLOC( len + 1 );
+		if ( NULL == *hostp ) {
+			return( LDAP_NO_MEMORY );
+		}
+		strncpy( *hostp, status->lhs_nexthost, len );
+		(*hostp)[len] = '\0';
+		status->lhs_nexthost += ( len + 1 );
+	} else {	/* last host */
+		*hostp = nsldapi_strdup( status->lhs_nexthost );
+		if ( NULL == *hostp ) {
+			return( LDAP_NO_MEMORY );
+		}
+		status->lhs_nexthost = NULL;
+	}
+
+	/* 
+	 * Look for closing ']' and skip past it before looking for port.
+	 */
+	if ( squarebrackets && NULL != ( q = strchr( *hostp, ']' ))) {
+		*q++ = '\0';
+	} else {
+		q = *hostp;
+	}
+
+	/* determine and set port */
+	if ( NULL != ( q = strchr( q, ':' ))) {
+		*q++ = '\0';
+		*portp = atoi( q );
+	} else {
+		*portp = status->lhs_defport;
+	}
+
+	return( LDAP_SUCCESS );
+}
+
+
+void LDAP_CALL
+ldap_x_hostlist_statusfree( struct ldap_x_hostlist_status *status )
+{
+	if ( NULL != status ) {
+		if ( NULL != status->lhs_hostlist ) {
+			NSLDAPI_FREE( status->lhs_hostlist );
+		}
+		NSLDAPI_FREE( status );
+	}
+}
+
+
+
+/*
+ * memory allocation functions.  we include these in open.c since every
+ *    LDAP application is likely to pull the rest of the code in this file
+ *    in anyways.
+ */
+void *
+ldap_x_malloc( size_t size )
+{
+	return( nsldapi_memalloc_fns.ldapmem_malloc == NULL ?
+	    malloc( size ) :
+	    nsldapi_memalloc_fns.ldapmem_malloc( size ));
+}
+
+
+void *
+ldap_x_calloc( size_t nelem, size_t elsize )
+{
+	return( nsldapi_memalloc_fns.ldapmem_calloc == NULL ?
+	    calloc(  nelem, elsize ) :
+	    nsldapi_memalloc_fns.ldapmem_calloc( nelem, elsize ));
+}
+
+
+void *
+ldap_x_realloc( void *ptr, size_t size )
+{
+	return( nsldapi_memalloc_fns.ldapmem_realloc == NULL ?
+	    realloc( ptr, size ) :
+	    nsldapi_memalloc_fns.ldapmem_realloc( ptr, size ));
+}
+
+
+void
+ldap_x_free( void *ptr )
+{
+	if ( nsldapi_memalloc_fns.ldapmem_free == NULL ) {
+		free( ptr );
+	} else {
+		nsldapi_memalloc_fns.ldapmem_free( ptr );
+	}
+}
+
+
+/* if s is NULL, returns NULL */
+char *
+nsldapi_strdup( const char *s )
+{
+	char	*p;
+
+	if ( s == NULL ||
+	    (p = (char *)NSLDAPI_MALLOC( strlen( s ) + 1 )) == NULL )
+		return( NULL );
+
+	strcpy( p, s );
+
+	return( p );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/os-ip.c
@@ -0,0 +1,1862 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ *  Copyright (c) 1995 Regents of the University of Michigan.
+ *  All rights reserved.
+ */
+/*
+ *  os-ip.c -- platform-specific TCP & UDP related code
+ */
+
+#if 0
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1995 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+/*
+ * On platforms where poll() does not exist, we use select().
+ * Therefore, we should increase the number of file descriptors
+ * we can use by #defining FD_SETSIZE to a large number before
+ * we include <sys/select.h> or its equivalent.  We do not need
+ * to do this for Windows, because on that platform there is no
+ * relationship between FD_SETSIZE and the highest numbered file
+ * descriptor we can use.  See the document fdsetsize.txt in
+ * this directory for a description of the setting of FD_SETSIZE
+ * for the OS'es we care about.
+ */
+#ifndef NSLDAPI_HAVE_POLL
+/* XXX value for BSDI? */
+/* XXX value for macintosh (if applicable)? */
+#endif
+
+#include "ldap-int.h"
+#ifdef NSLDAPI_CONNECT_MUST_NOT_BE_INTERRUPTED
+#include <signal.h>
+#endif
+
+#ifdef NSLDAPI_HAVE_POLL
+#include <poll.h>
+#endif
+
+
+#ifdef _WINDOWS
+#define NSLDAPI_INVALID_OS_SOCKET( s )	((s) == INVALID_SOCKET)
+#else
+#define NSLDAPI_INVALID_OS_SOCKET( s )	((s) < 0 )	
+#endif
+
+
+#define NSLDAPI_POLL_ARRAY_GROWTH  5  /* grow arrays 5 elements at a time */
+
+
+/*
+ * Structures and union for tracking status of network sockets
+ */
+#ifdef NSLDAPI_HAVE_POLL
+struct nsldapi_os_statusinfo {		/* used with native OS poll() */
+	struct pollfd		*ossi_pollfds;
+	int			ossi_pollfds_size;
+};
+#else /* NSLDAPI_HAVE_POLL */
+struct nsldapi_os_statusinfo {		/* used with native OS select() */
+	fd_set			ossi_readfds;
+	fd_set			ossi_writefds;
+	fd_set			ossi_use_readfds;
+	fd_set			ossi_use_writefds;
+};
+#endif /* else NSLDAPI_HAVE_POLL */
+
+struct nsldapi_cb_statusinfo {		/* used with ext. I/O poll() callback */
+    LDAP_X_PollFD		*cbsi_pollfds;
+    int				cbsi_pollfds_size;
+};
+
+/*
+ * NSLDAPI_CB_POLL_MATCH() evaluates to non-zero (true) if the Sockbuf *sdp
+ * matches the LDAP_X_PollFD pollfd.
+ */
+#ifdef _WINDOWS
+#define NSLDAPI_CB_POLL_SD_CAST		(unsigned int)
+#else
+#define NSLDAPI_CB_POLL_SD_CAST
+#endif
+#define NSLDAPI_CB_POLL_MATCH( sbp, pollfd ) \
+    ((sbp)->sb_sd == NSLDAPI_CB_POLL_SD_CAST ((pollfd).lpoll_fd) && \
+    (sbp)->sb_ext_io_fns.lbextiofn_socket_arg == (pollfd).lpoll_socketarg)
+
+
+struct nsldapi_iostatus_info {
+	int				ios_type;
+#define NSLDAPI_IOSTATUS_TYPE_OSNATIVE		1   /* poll() or select() */
+#define NSLDAPI_IOSTATUS_TYPE_CALLBACK		2   /* poll()-like */
+	int				ios_read_count;
+	int				ios_write_count;
+	union {
+	    struct nsldapi_os_statusinfo	ios_osinfo;
+	    struct nsldapi_cb_statusinfo	ios_cbinfo;
+	} ios_status;
+};
+
+#ifndef NSLDAPI_AVOID_OS_SOCKETS
+#ifdef NSLDAPI_HAVE_POLL
+static int nsldapi_add_to_os_pollfds( int fd,
+    struct nsldapi_os_statusinfo *pip, short events );
+static int nsldapi_clear_from_os_pollfds( int fd,
+    struct nsldapi_os_statusinfo *pip, short events );
+static int nsldapi_find_in_os_pollfds( int fd,
+    struct nsldapi_os_statusinfo *pip, short revents );
+#endif /* NSLDAPI_HAVE_POLL */
+#endif /* NSLDAPI_AVOID_OS_SOCKETS */
+
+static int nsldapi_iostatus_init_nolock( LDAP *ld );
+static int nsldapi_add_to_cb_pollfds( Sockbuf *sb,
+    struct nsldapi_cb_statusinfo *pip, short events );
+static int nsldapi_clear_from_cb_pollfds( Sockbuf *sb,
+    struct nsldapi_cb_statusinfo *pip, short events );
+static int nsldapi_find_in_cb_pollfds( Sockbuf *sb,
+    struct nsldapi_cb_statusinfo *pip, short revents );
+
+
+#ifdef irix
+#ifndef _PR_THREADS
+/*
+ * XXXmcs: on IRIX NSPR's poll() and select() wrappers will crash if NSPR
+ * has not been initialized.  We work around the problem by bypassing
+ * the NSPR wrapper functions and going directly to the OS' functions.
+ */
+#define NSLDAPI_POLL		_poll
+#define NSLDAPI_SELECT		_select
+extern int _poll(struct pollfd *fds, unsigned long nfds, int timeout);
+extern int _select(int nfds, fd_set *readfds, fd_set *writefds,
+        fd_set *exceptfds, struct timeval *timeout);
+#else /* _PR_THREADS */
+#define NSLDAPI_POLL		poll
+#define NSLDAPI_SELECT		select
+#endif /* else _PR_THREADS */
+#else /* irix */
+#define NSLDAPI_POLL		poll
+#define NSLDAPI_SELECT		select
+#endif /* else irix */
+
+
+static LBER_SOCKET nsldapi_os_socket( LDAP *ld, int secure, int domain,
+	int type, int protocol );
+static int nsldapi_os_ioctl( LBER_SOCKET s, int option, int *statusp );
+static int nsldapi_os_connect_with_to( LBER_SOCKET s, struct sockaddr *name,
+	int namelen, int msec_timeout );
+#if defined(KERBEROS)
+char * nsldapi_host_connected_to( LDAP *ld, Sockbuf *sb );
+#endif
+
+/*
+ * Function typedefs used by nsldapi_try_each_host()
+ */
+typedef LBER_SOCKET (NSLDAPI_SOCKET_FN)( LDAP *ld, int secure, int domain,
+	    int type, int protocol );
+typedef int (NSLDAPI_IOCTL_FN)( LBER_SOCKET s, int option, int *statusp );
+typedef int (NSLDAPI_CONNECT_WITH_TO_FN )( LBER_SOCKET s, struct sockaddr *name,
+	int namelen, int msec_timeout );
+typedef int (NSLDAPI_CONNECT_FN )( LBER_SOCKET s, struct sockaddr *name,
+	int namelen );
+typedef int (NSLDAPI_CLOSE_FN )( LBER_SOCKET s );
+
+static int nsldapi_try_each_host( LDAP *ld, const char *hostlist, int defport,
+	int secure, NSLDAPI_SOCKET_FN *socketfn, NSLDAPI_IOCTL_FN *ioctlfn,
+	NSLDAPI_CONNECT_WITH_TO_FN *connectwithtofn,
+	NSLDAPI_CONNECT_FN *connectfn, NSLDAPI_CLOSE_FN *closefn );
+
+
+static int
+nsldapi_os_closesocket( LBER_SOCKET s )
+{
+	int	rc;
+
+#ifdef NSLDAPI_AVOID_OS_SOCKETS
+	rc = -1;
+#else /* NSLDAPI_AVOID_OS_SOCKETS */
+#ifdef _WINDOWS
+	rc = closesocket( s );
+#else /* _WINDOWS */
+	rc = close( s );
+#endif /* _WINDOWS */
+#endif /* NSLDAPI_AVOID_OS_SOCKETS */
+	return( rc );
+}
+
+
+static LBER_SOCKET
+nsldapi_os_socket( LDAP *ld, int secure, int domain, int type, int protocol )
+{
+#ifdef NSLDAPI_AVOID_OS_SOCKETS
+	return -1;
+#else /* NSLDAPI_AVOID_OS_SOCKETS */
+	int		s, invalid_socket;
+	char		*errmsg = NULL;
+
+	if ( secure ) {
+		LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL,
+			    nsldapi_strdup( "secure mode not supported" ));
+		return( -1 );
+	}
+
+	s = socket( domain, type, protocol );
+
+	/*
+	 * if the socket() call failed or it returned a socket larger
+	 * than we can deal with, return a "local error."
+	 */
+	if ( NSLDAPI_INVALID_OS_SOCKET( s )) {
+		errmsg = "unable to create a socket";
+		invalid_socket = 1;
+	} else {	/* valid socket -- check for overflow */
+		invalid_socket = 0;
+#if !defined(NSLDAPI_HAVE_POLL) && !defined(_WINDOWS)
+		/* not on Windows and do not have poll() */
+		if ( s >= FD_SETSIZE ) {
+			errmsg = "can't use socket >= FD_SETSIZE";
+		}
+#endif
+	}
+
+	if ( errmsg != NULL ) {	/* local socket error */
+		if ( !invalid_socket ) {
+			nsldapi_os_closesocket( s );
+		}
+		errmsg = nsldapi_strdup( errmsg );
+		LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL, errmsg );
+		return( -1 );
+	}
+
+	return( s );
+#endif /* NSLDAPI_AVOID_OS_SOCKETS */
+}
+
+
+
+/*
+ * Non-blocking connect call function
+ */
+static int
+nsldapi_os_connect_with_to(LBER_SOCKET sockfd, struct sockaddr *saptr,
+	int salen, int msec)
+{
+#ifdef NSLDAPI_AVOID_OS_SOCKETS
+	return -1;
+#else /* NSLDAPI_AVOID_OS_SOCKETS */
+	int		n, error;
+	int		len;
+#if defined(_WINDOWS) || defined(XP_OS2)
+	int		nonblock = 1;
+	int		block = 0;
+#else
+	int		flags;
+#endif /* _WINDOWS */
+#ifdef NSLDAPI_HAVE_POLL
+	struct pollfd   pfd;
+#else
+	struct timeval	tval;
+	fd_set		rset, wset;
+#ifdef _WINDOWS
+	fd_set		eset;
+#endif
+#endif /* NSLDAPI_HAVE_POLL */
+
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_connect_nonblock timeout: %d (msec)\n",
+		msec, 0, 0);
+
+#ifdef _WINDOWS
+	ioctlsocket(sockfd, FIONBIO, &nonblock);
+#elif defined(XP_OS2)
+  ioctl( sockfd, FIONBIO, &nonblock, sizeof(nonblock) );
+#else
+	flags = fcntl(sockfd, F_GETFL, 0);
+	fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
+#endif /* _WINDOWS */
+
+	error = 0;
+	if ((n = connect(sockfd, saptr, salen)) < 0)
+#ifdef _WINDOWS
+		if ((n != SOCKET_ERROR) &&  (WSAGetLastError() != WSAEWOULDBLOCK)) {
+#else
+		if (errno != EINPROGRESS) {
+#endif /* _WINDOWS */
+#ifdef LDAP_DEBUG
+			if ( ldap_debug & LDAP_DEBUG_TRACE ) {
+				perror("connect");
+			}
+#endif
+			return (-1);
+		}
+
+	/* success */
+	if (n == 0)
+		goto done;
+
+#ifdef NSLDAPI_HAVE_POLL
+	pfd.fd = sockfd;
+	pfd.events = POLLOUT;
+#else
+	FD_ZERO(&rset);
+	FD_SET(sockfd, &rset);
+	wset = rset;
+
+#ifdef _WINDOWS
+	eset = rset;
+#endif /* _WINDOWS */
+#endif /* NSLDAPI_HAVE_POLL */
+
+	if (msec < 0 && msec != LDAP_X_IO_TIMEOUT_NO_TIMEOUT) {
+		LDAPDebug( LDAP_DEBUG_TRACE, "Invalid timeout value detected.."
+			"resetting connect timeout to default value "
+			"(LDAP_X_IO_TIMEOUT_NO_TIMEOUT\n", 0, 0, 0);
+		msec = LDAP_X_IO_TIMEOUT_NO_TIMEOUT;
+#ifndef NSLDAPI_HAVE_POLL
+	} else {
+		if (msec != 0) {
+			tval.tv_sec = msec / 1000;
+			tval.tv_usec = 1000 * ( msec % 1000 );
+		} else {
+			tval.tv_sec = 0;
+			tval.tv_usec = 0;
+		}
+#endif /* NSLDAPI_HAVE_POLL */
+	}
+
+#ifdef NSLDAPI_HAVE_POLL
+	if ((n = poll(&pfd, 1,
+		(msec != LDAP_X_IO_TIMEOUT_NO_TIMEOUT) ? msec : -1)) == 0) {
+		errno = ETIMEDOUT;
+		return (-1);
+	}
+	if (pfd.revents & (POLLOUT|POLLERR|POLLHUP|POLLNVAL)) {
+		len = sizeof(error);
+		if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char *)&error, &len)
+			< 0)
+			return (-1);
+#ifdef LDAP_DEBUG
+	} else if ( ldap_debug & LDAP_DEBUG_TRACE ) {
+		perror("poll error: sockfd not set");
+#endif
+	}
+
+#else /* NSLDAPI_HAVE_POLL */
+	/* if timeval structure == NULL, select will block indefinitely */
+	/* 			!= NULL, and value == 0, select will */
+	/* 			         not block */
+	/* Windows is a bit quirky on how it behaves w.r.t nonblocking */
+	/* connects.  If the connect fails, the exception fd, eset, is */
+	/* set to show the failure.  The first argument in select is */
+	/* ignored */
+
+#ifdef _WINDOWS
+	if ((n = select(sockfd +1, &rset, &wset, &eset,
+		(msec != LDAP_X_IO_TIMEOUT_NO_TIMEOUT) ? &tval : NULL)) == 0) {
+		errno = WSAETIMEDOUT;
+		return (-1);
+	}
+	/* if wset is set, the connect worked */
+	if (FD_ISSET(sockfd, &wset) || FD_ISSET(sockfd, &rset)) {
+		len = sizeof(error);
+		if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char *)&error, &len)
+			< 0)
+			return (-1);
+		goto done;
+	}
+
+	/* if eset is set, the connect failed */
+	if (FD_ISSET(sockfd, &eset)) {
+		return (-1);
+	}
+
+	/* failure on select call */
+	if (n == SOCKET_ERROR) {
+		perror("select error: SOCKET_ERROR returned");
+		return (-1);		
+	}
+#else
+	if ((n = select(sockfd +1, &rset, &wset, NULL,
+		(msec != LDAP_X_IO_TIMEOUT_NO_TIMEOUT) ? &tval : NULL)) == 0) {
+		errno = ETIMEDOUT;
+		return (-1);
+	}
+	if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) {
+		len = sizeof(error);
+		if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char *)&error, &len)
+			< 0)
+			return (-1);
+#ifdef LDAP_DEBUG
+	} else if ( ldap_debug & LDAP_DEBUG_TRACE ) {
+		perror("select error: sockfd not set");
+#endif
+	}
+#endif /* _WINDOWS */
+#endif /* NSLDAPI_HAVE_POLL */
+
+done:
+#ifdef _WINDOWS
+	ioctlsocket(sockfd, FIONBIO, &block);
+#elif defined(XP_OS2)
+  ioctl( sockfd, FIONBIO, &nonblock, sizeof(block) );
+#else
+	fcntl(sockfd, F_SETFL, flags);
+#endif /* _WINDOWS */
+
+	if (error) {
+		errno = error;
+		return (-1);
+	}
+
+	return (0);
+#endif /* NSLDAPI_AVOID_OS_SOCKETS */
+}
+
+
+static int
+nsldapi_os_ioctl( LBER_SOCKET s, int option, int *statusp )
+{
+#ifdef NSLDAPI_AVOID_OS_SOCKETS
+	return -1;
+#else /* NSLDAPI_AVOID_OS_SOCKETS */
+	int		err;
+#if defined(_WINDOWS) || defined(XP_OS2)
+	u_long		iostatus;
+#endif
+
+	if ( FIONBIO != option ) {
+		return( -1 );
+	}
+
+#ifdef _WINDOWS
+	iostatus = *(u_long *)statusp;
+	err = ioctlsocket( s, FIONBIO, &iostatus );
+#else
+#ifdef XP_OS2
+	err = ioctl( s, FIONBIO, (caddr_t)&iostatus, sizeof(iostatus) );
+#else
+	err = ioctl( s, FIONBIO, (caddr_t)statusp );
+#endif
+#endif
+
+	return( err );
+#endif /* NSLDAPI_AVOID_OS_SOCKETS */
+}
+
+
+int
+nsldapi_connect_to_host( LDAP *ld, Sockbuf *sb, const char *hostlist,
+		int defport, int secure, char **krbinstancep )
+/*
+ * "defport" must be in host byte order
+ * zero is returned upon success, -1 if fatal error, -2 EINPROGRESS
+ * if -1 is returned, ld_errno is set
+ */
+{
+	int		s;
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_connect_to_host: %s, port: %d\n",
+	    NULL == hostlist ? "NULL" : hostlist, defport, 0 );
+
+	/*
+	 * If an extended I/O connect callback has been defined, just use it.
+	 */
+	if ( NULL != ld->ld_extconnect_fn ) {
+		unsigned long connect_opts = 0;
+
+		if ( ld->ld_options & LDAP_BITOPT_ASYNC) {
+			connect_opts |= LDAP_X_EXTIOF_OPT_NONBLOCKING;
+		}
+		if ( secure ) {
+			connect_opts |= LDAP_X_EXTIOF_OPT_SECURE;
+		}
+		s = ld->ld_extconnect_fn( hostlist, defport,
+		    ld->ld_connect_timeout, connect_opts,
+		    ld->ld_ext_session_arg,
+		    &sb->sb_ext_io_fns.lbextiofn_socket_arg );
+
+	} else {
+#ifdef NSLDAPI_AVOID_OS_SOCKETS
+		return( -1 );
+#else /* NSLDAPI_AVOID_OS_SOCKETS */
+		s = nsldapi_try_each_host( ld, hostlist,
+			defport, secure, nsldapi_os_socket,
+			nsldapi_os_ioctl, nsldapi_os_connect_with_to,
+			NULL, nsldapi_os_closesocket );
+#endif /* NSLDAPI_AVOID_OS_SOCKETS */
+	}
+
+	if ( s < 0 ) {
+		LDAP_SET_LDERRNO( ld, LDAP_CONNECT_ERROR, NULL, NULL );
+		return( -1 );
+	}
+
+	sb->sb_sd = s;
+
+	/*
+	 * Set krbinstancep (canonical name of host for use by Kerberos).
+	 */
+#ifdef KERBEROS
+	char	*p;
+
+	if (( *krbinstancep = nsldapi_host_connected_to( sb )) != NULL
+	    && ( p = strchr( *krbinstancep, '.' )) != NULL ) {
+		*p = '\0';
+	}
+#else /* KERBEROS */
+	*krbinstancep = NULL;
+#endif /* KERBEROS */
+
+	return( 0 );
+}
+
+
+/*
+ * Returns a socket number if successful and -1 if an error occurs.
+ */
+static int
+nsldapi_try_each_host( LDAP *ld, const char *hostlist,
+	int defport, int secure, NSLDAPI_SOCKET_FN *socketfn,
+	NSLDAPI_IOCTL_FN *ioctlfn, NSLDAPI_CONNECT_WITH_TO_FN *connectwithtofn,
+	NSLDAPI_CONNECT_FN *connectfn, NSLDAPI_CLOSE_FN *closefn )
+{
+#ifdef NSLDAPI_AVOID_OS_SOCKETS
+	return -1;
+#else /* NSLDAPI_AVOID_OS_SOCKETS */
+	int			rc = -1;
+	int			s = 0;
+	int			i, err, connected, use_hp;
+	int			parse_err, port;
+	struct sockaddr_in	sin;
+	nsldapi_in_addr_t	address;
+	char			**addrlist, *ldhpbuf, *ldhpbuf_allocd = NULL;
+	char			*host;
+	LDAPHostEnt		ldhent, *ldhp;
+	struct hostent		*hp;
+	struct ldap_x_hostlist_status	*status;
+#ifdef GETHOSTBYNAME_BUF_T
+	GETHOSTBYNAME_BUF_T	hbuf;
+	struct hostent		hent;
+#endif /* GETHOSTBYNAME_BUF_T */
+
+	connected = 0;
+	parse_err = ldap_x_hostlist_first( hostlist, defport, &host, &port,
+            &status );
+	while ( !connected && LDAP_SUCCESS == parse_err && host != NULL ) {
+		ldhpbuf_allocd = NULL;
+		ldhp = NULL;
+		hp = NULL;
+		s = 0;
+		use_hp = 0;
+		addrlist = NULL;
+
+
+		if (( address = inet_addr( host )) == -1 ) {
+			if ( ld->ld_dns_gethostbyname_fn == NULL ) {
+#ifdef GETHOSTBYNAME_R_RETURNS_INT
+				(void)GETHOSTBYNAME( host, &hent, hbuf,
+				    sizeof(hbuf), &hp, &err );
+#else
+				hp = GETHOSTBYNAME( host, &hent, hbuf,
+				    sizeof(hbuf), &err );
+#endif
+				if ( hp != NULL ) {
+					addrlist = hp->h_addr_list;
+				}
+			} else {
+				/*
+				 * DNS callback installed... use it.
+				 */
+#ifdef GETHOSTBYNAME_buf_t
+				/* avoid allocation by using hbuf if large enough */
+				if ( sizeof( hbuf ) < ld->ld_dns_bufsize ) {
+					ldhpbuf = ldhpbuf_allocd
+					    = NSLDAPI_MALLOC( ld->ld_dns_bufsize );
+				} else {
+					ldhpbuf = (char *)hbuf;
+				}
+#else /* GETHOSTBYNAME_buf_t */
+				ldhpbuf = ldhpbuf_allocd = NSLDAPI_MALLOC(
+				    ld->ld_dns_bufsize );
+#endif /* else GETHOSTBYNAME_buf_t */
+
+				if ( ldhpbuf == NULL ) {
+					LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY,
+					    NULL, NULL );
+					ldap_memfree( host );
+					ldap_x_hostlist_statusfree( status );
+					return( -1 );
+				}
+
+				if (( ldhp = ld->ld_dns_gethostbyname_fn( host,
+				    &ldhent, ldhpbuf, ld->ld_dns_bufsize, &err,
+				    ld->ld_dns_extradata )) != NULL ) {
+					addrlist = ldhp->ldaphe_addr_list;
+				}
+			}
+
+			if ( addrlist == NULL ) {
+				LDAP_SET_LDERRNO( ld, LDAP_CONNECT_ERROR, NULL, NULL );
+				LDAP_SET_ERRNO( ld, EHOSTUNREACH );  /* close enough */
+				if ( ldhpbuf_allocd != NULL ) {
+					NSLDAPI_FREE( ldhpbuf_allocd );
+				}
+				ldap_memfree( host );
+				ldap_x_hostlist_statusfree( status );
+				return( -1 );
+			}
+			use_hp = 1;
+		}
+
+		rc = -1;
+		for ( i = 0; !use_hp || ( addrlist[ i ] != 0 ); i++ ) {
+			if ( -1 == ( s = (*socketfn)( ld, secure, AF_INET,
+					SOCK_STREAM, 0 ))) {
+				if ( ldhpbuf_allocd != NULL ) {
+					NSLDAPI_FREE( ldhpbuf_allocd );
+				}
+				ldap_memfree( host );
+				ldap_x_hostlist_statusfree( status );
+				return( -1 );
+			}
+
+			if ( ld->ld_options & LDAP_BITOPT_ASYNC ) {
+				int	iostatus = 1;
+
+				err = (*ioctlfn)( s, FIONBIO, &iostatus );
+				if ( err == -1 ) {
+					LDAPDebug( LDAP_DEBUG_ANY,
+					    "FIONBIO ioctl failed on %d\n",
+					    s, 0, 0 );
+				}
+			}
+
+			(void)memset( (char *)&sin, 0, sizeof( struct sockaddr_in ));
+			sin.sin_family = AF_INET;
+			sin.sin_port = htons( (unsigned short)port );
+
+			SAFEMEMCPY( (char *) &sin.sin_addr.s_addr,
+			    ( use_hp ? (char *) addrlist[ i ] :
+			    (char *) &address ), sizeof( sin.sin_addr.s_addr) );
+
+			{
+#ifdef NSLDAPI_CONNECT_MUST_NOT_BE_INTERRUPTED
+/*
+ * Block all of the signals that might interrupt connect() since
+ * there is an OS bug that causes connect() to fail if it is restarted.
+ * Look in ../../include/portable.h for the definition of
+ * NSLDAPI_CONNECT_MUST_NOT_BE_INTERRUPTED.
+ */
+				sigset_t	ints_off, oldset;
+
+				sigemptyset( &ints_off );
+				sigaddset( &ints_off, SIGALRM );
+				sigaddset( &ints_off, SIGIO );
+				sigaddset( &ints_off, SIGCLD );
+
+				NSLDAPI_MT_SAFE_SIGPROCMASK( SIG_BLOCK, &ints_off, &oldset );
+#endif /* NSLDAPI_CONNECT_MUST_NOT_BE_INTERRUPTED */
+
+				if ( NULL != connectwithtofn  ) {	
+					err = (*connectwithtofn)(s,
+						(struct sockaddr *)&sin,
+						sizeof(struct sockaddr_in),
+						ld->ld_connect_timeout);
+				} else {
+					err = (*connectfn)(s,
+						(struct sockaddr *)&sin,
+						sizeof(struct sockaddr_in));
+				}
+#ifdef NSLDAPI_CONNECT_MUST_NOT_BE_INTERRUPTED
+/*
+ * restore original signal mask
+ */
+				NSLDAPI_MT_SAFE_SIGPROCMASK( SIG_SETMASK, &oldset, 0 );
+#endif /* NSLDAPI_CONNECT_MUST_NOT_BE_INTERRUPTED */
+
+			}
+			if ( err >= 0 ) {
+				connected = 1;
+				rc = 0;
+				break;
+			} else {
+				if ( ld->ld_options & LDAP_BITOPT_ASYNC) {
+#ifdef _WINDOWS
+					if (err == -1 && WSAGetLastError() == WSAEWOULDBLOCK)
+						LDAP_SET_ERRNO( ld, EWOULDBLOCK );
+#endif /* _WINDOWS */
+					err = LDAP_GET_ERRNO( ld );
+					if ( NSLDAPI_ERRNO_IO_INPROGRESS( err )) {
+						LDAPDebug( LDAP_DEBUG_TRACE, "connect would block...\n",
+							   0, 0, 0 );
+						rc = -2;
+						break;
+					}
+				}
+
+#ifdef LDAP_DEBUG
+				if ( ldap_debug & LDAP_DEBUG_TRACE ) {
+					perror( (char *)inet_ntoa( sin.sin_addr ));
+				}
+#endif
+				(*closefn)( s );
+				if ( !use_hp ) {
+					break;
+				}
+			}
+		}
+
+		ldap_memfree( host );
+		parse_err = ldap_x_hostlist_next( &host, &port, status );
+	}
+
+	if ( ldhpbuf_allocd != NULL ) {
+		NSLDAPI_FREE( ldhpbuf_allocd );
+	}
+	ldap_memfree( host );
+	ldap_x_hostlist_statusfree( status );
+
+	if ( connected ) {
+		LDAPDebug( LDAP_DEBUG_TRACE, "sd %d connected to: %s\n",
+		    s, inet_ntoa( sin.sin_addr ), 0 );
+	}
+
+	return( rc == 0 ? s : -1 );
+#endif /* NSLDAPI_AVOID_OS_SOCKETS */
+}
+
+void
+nsldapi_close_connection( LDAP *ld, Sockbuf *sb )
+{
+	if ( ld->ld_extclose_fn == NULL ) {
+#ifndef NSLDAPI_AVOID_OS_SOCKETS
+		nsldapi_os_closesocket( sb->sb_sd );
+#endif /* NSLDAPI_AVOID_OS_SOCKETS */
+	} else {
+		ld->ld_extclose_fn( sb->sb_sd,
+			    sb->sb_ext_io_fns.lbextiofn_socket_arg );
+	}
+}
+
+
+#ifdef KERBEROS
+char *
+nsldapi_host_connected_to( LDAP *ld, Sockbuf *sb )
+{
+	struct hostent		*hp;
+	char			*p;
+	int			len;
+	struct sockaddr_in	sin;
+
+	(void)memset( (char *)&sin, 0, sizeof( struct sockaddr_in ));
+	len = sizeof( sin );
+	if ( getpeername( sb->sb_sd, (struct sockaddr *)&sin, &len ) == -1 ) {
+		return( NULL );
+	}
+
+	/*
+	 * do a reverse lookup on the addr to get the official hostname.
+	 * this is necessary for kerberos to work right, since the official
+	 * hostname is used as the kerberos instance.
+	 */
+#error XXXmcs: need to use DNS callbacks here
+	if (( hp = (struct hostent *)gethostbyaddr( (char *) &sin.sin_addr,
+	    sizeof( sin.sin_addr ), AF_INET )) != NULL ) {
+		if ( hp->h_name != NULL ) {
+			return( nsldapi_strdup( hp->h_name ));
+		}
+	}
+
+	return( NULL );
+}
+#endif /* KERBEROS */
+
+
+/*
+ * Returns 0 if all goes well and -1 if an error occurs (error code set in ld)
+ * Also allocates initializes ld->ld_iostatus if needed..
+ */
+int
+nsldapi_iostatus_interest_write( LDAP *ld, Sockbuf *sb )
+{
+	int		rc = 0;
+	NSLDAPIIOStatus	*iosp;
+
+	LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
+
+	if ( ld->ld_iostatus == NULL
+	    && nsldapi_iostatus_init_nolock( ld ) < 0 ) {
+		rc = -1;
+		goto unlock_and_return;
+	}
+
+	iosp = ld->ld_iostatus;
+
+	if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
+#ifdef NSLDAPI_AVOID_OS_SOCKETS
+		rc = -1;
+		goto unlock_and_return;
+#else /* NSLDAPI_AVOID_OS_SOCKETS */
+#ifdef NSLDAPI_HAVE_POLL
+		if ( nsldapi_add_to_os_pollfds( sb->sb_sd,
+		    &iosp->ios_status.ios_osinfo, POLLOUT )) {
+			++iosp->ios_write_count;
+		}
+#else /* NSLDAPI_HAVE_POLL */
+		if ( !FD_ISSET( sb->sb_sd,
+		    &iosp->ios_status.ios_osinfo.ossi_writefds )) {
+			FD_SET( sb->sb_sd,
+			    &iosp->ios_status.ios_osinfo.ossi_writefds );
+			++iosp->ios_write_count;
+		}
+#endif /* else NSLDAPI_HAVE_POLL */
+#endif /* NSLDAPI_AVOID_OS_SOCKETS */
+
+	} else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_CALLBACK ) {
+		if ( nsldapi_add_to_cb_pollfds( sb,
+		    &iosp->ios_status.ios_cbinfo, LDAP_X_POLLOUT )) {
+			++iosp->ios_write_count;
+		}
+
+	} else {
+		LDAPDebug( LDAP_DEBUG_ANY,
+		    "nsldapi_iostatus_interest_write: unknown I/O type %d\n",
+		     iosp->ios_type, 0, 0 );
+	}
+
+unlock_and_return:
+	LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
+	return( rc );
+}
+
+
+/*
+ * Returns 0 if all goes well and -1 if an error occurs (error code set in ld)
+ * Also allocates initializes ld->ld_iostatus if needed..
+ */
+int
+nsldapi_iostatus_interest_read( LDAP *ld, Sockbuf *sb )
+{
+	int		rc = 0;
+	NSLDAPIIOStatus	*iosp;
+
+	LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
+
+	if ( ld->ld_iostatus == NULL
+	    && nsldapi_iostatus_init_nolock( ld ) < 0 ) {
+		rc = -1;
+		goto unlock_and_return;
+	}
+
+	iosp = ld->ld_iostatus;
+
+	if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
+#ifdef NSLDAPI_AVOID_OS_SOCKETS
+		rc = -1;
+		goto unlock_and_return;
+#else /* NSLDAPI_AVOID_OS_SOCKETS */
+#ifdef NSLDAPI_HAVE_POLL
+		if ( nsldapi_add_to_os_pollfds( sb->sb_sd,
+		    &iosp->ios_status.ios_osinfo, POLLIN )) {
+			++iosp->ios_read_count;
+		}
+#else /* NSLDAPI_HAVE_POLL */
+		if ( !FD_ISSET( sb->sb_sd,
+		    &iosp->ios_status.ios_osinfo.ossi_readfds )) {
+			FD_SET( sb->sb_sd,
+			    &iosp->ios_status.ios_osinfo.ossi_readfds );
+			++iosp->ios_read_count;
+		}
+#endif /* else NSLDAPI_HAVE_POLL */
+#endif /* NSLDAPI_AVOID_OS_SOCKETS */
+
+	} else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_CALLBACK ) {
+		if ( nsldapi_add_to_cb_pollfds( sb,
+		    &iosp->ios_status.ios_cbinfo, LDAP_X_POLLIN )) {
+			++iosp->ios_read_count;
+		}
+	} else {
+		LDAPDebug( LDAP_DEBUG_ANY,
+		    "nsldapi_iostatus_interest_read: unknown I/O type %d\n",
+		     iosp->ios_type, 0, 0 );
+	}
+
+unlock_and_return:
+	LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
+	return( rc );
+}
+
+
+/*
+ * Returns 0 if all goes well and -1 if an error occurs (error code set in ld)
+ * Also allocates initializes ld->ld_iostatus if needed..
+ */
+int
+nsldapi_iostatus_interest_clear( LDAP *ld, Sockbuf *sb )
+{
+	int		rc = 0;
+	NSLDAPIIOStatus	*iosp;
+
+	LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
+
+	if ( ld->ld_iostatus == NULL
+	    && nsldapi_iostatus_init_nolock( ld ) < 0 ) {
+		rc = -1;
+		goto unlock_and_return;
+	}
+
+	iosp = ld->ld_iostatus;
+
+	if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
+#ifdef NSLDAPI_AVOID_OS_SOCKETS
+		rc = -1;
+		goto unlock_and_return;
+#else /* NSLDAPI_AVOID_OS_SOCKETS */
+#ifdef NSLDAPI_HAVE_POLL
+		if ( nsldapi_clear_from_os_pollfds( sb->sb_sd,
+		    &iosp->ios_status.ios_osinfo, POLLOUT )) {
+			--iosp->ios_write_count;
+		}
+		if ( nsldapi_clear_from_os_pollfds( sb->sb_sd,
+		    &iosp->ios_status.ios_osinfo, POLLIN )) {
+			--iosp->ios_read_count;
+		}
+#else /* NSLDAPI_HAVE_POLL */
+		if ( FD_ISSET( sb->sb_sd,
+		    &iosp->ios_status.ios_osinfo.ossi_writefds )) {
+			FD_CLR( sb->sb_sd,
+			    &iosp->ios_status.ios_osinfo.ossi_writefds );
+			--iosp->ios_write_count;
+		}
+		if ( FD_ISSET( sb->sb_sd,
+		    &iosp->ios_status.ios_osinfo.ossi_readfds )) {
+			FD_CLR( sb->sb_sd,
+			    &iosp->ios_status.ios_osinfo.ossi_readfds );
+			--iosp->ios_read_count;
+		}
+#endif /* else NSLDAPI_HAVE_POLL */
+#endif /* NSLDAPI_AVOID_OS_SOCKETS */
+
+	} else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_CALLBACK ) {
+		if ( nsldapi_clear_from_cb_pollfds( sb,
+		    &iosp->ios_status.ios_cbinfo, LDAP_X_POLLOUT )) {
+			--iosp->ios_write_count;
+		}
+		if ( nsldapi_clear_from_cb_pollfds( sb,
+		    &iosp->ios_status.ios_cbinfo, LDAP_X_POLLIN )) {
+			--iosp->ios_read_count;
+		}
+	} else {
+		LDAPDebug( LDAP_DEBUG_ANY,
+		    "nsldapi_iostatus_interest_clear: unknown I/O type %d\n",
+		     iosp->ios_type, 0, 0 );
+	}
+
+unlock_and_return:
+	LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
+	return( rc );
+}
+
+
+/*
+ * Return a non-zero value if sb is ready for write.
+ */
+int
+nsldapi_iostatus_is_write_ready( LDAP *ld, Sockbuf *sb )
+{
+	int		rc = 0;
+	NSLDAPIIOStatus	*iosp;
+
+	LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
+	iosp = ld->ld_iostatus;
+	if ( iosp == NULL ) {
+		goto unlock_and_return;
+	}
+
+	if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
+#ifdef NSLDAPI_AVOID_OS_SOCKETS
+		goto unlock_and_return;
+#else  /* NSLDAPI_AVOID_OS_SOCKETS */
+#ifdef NSLDAPI_HAVE_POLL
+		/*
+		 * if we are using poll() we do something a little tricky: if
+		 * any bits in the socket's returned events field other than
+		 * POLLIN (ready for read) are set, we return true.  This
+		 * is done so we notice when a server closes a connection
+		 * or when another error occurs.  The actual error will be
+		 * noticed later when we call write() or send().
+		 */
+		rc = nsldapi_find_in_os_pollfds( sb->sb_sd,
+		    &iosp->ios_status.ios_osinfo, ~POLLIN );
+
+#else /* NSLDAPI_HAVE_POLL */
+		rc = FD_ISSET( sb->sb_sd,
+			&iosp->ios_status.ios_osinfo.ossi_use_writefds );
+#endif /* else NSLDAPI_HAVE_POLL */
+#endif /* NSLDAPI_AVOID_OS_SOCKETS */
+
+	} else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_CALLBACK ) {
+		rc = nsldapi_find_in_cb_pollfds( sb,
+		    &iosp->ios_status.ios_cbinfo, ~LDAP_X_POLLIN );
+
+	} else {
+		LDAPDebug( LDAP_DEBUG_ANY,
+		    "nsldapi_iostatus_is_write_ready: unknown I/O type %d\n",
+		     iosp->ios_type, 0, 0 );
+		rc = 0;
+	}
+
+unlock_and_return:
+	LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
+	return( rc );
+}
+
+
+/*
+ * Return a non-zero value if sb is ready for read.
+ */
+int
+nsldapi_iostatus_is_read_ready( LDAP *ld, Sockbuf *sb )
+{
+	int		rc = 0;
+	NSLDAPIIOStatus	*iosp;
+
+	LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
+	iosp = ld->ld_iostatus;
+	if ( iosp == NULL ) {
+		goto unlock_and_return;
+	}
+
+	if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
+#ifdef NSLDAPI_AVOID_OS_SOCKETS
+		goto unlock_and_return;
+#else /* NSLDAPI_AVOID_OS_SOCKETS */
+#ifdef NSLDAPI_HAVE_POLL
+		/*
+		 * if we are using poll() we do something a little tricky: if
+		 * any bits in the socket's returned events field other than
+		 * POLLOUT (ready for write) are set, we return true.  This
+		 * is done so we notice when a server closes a connection
+		 * or when another error occurs.  The actual error will be
+		 * noticed later when we call read() or recv().
+		 */
+		rc = nsldapi_find_in_os_pollfds( sb->sb_sd,
+		    &iosp->ios_status.ios_osinfo, ~POLLOUT );
+
+#else /* NSLDAPI_HAVE_POLL */
+		rc = FD_ISSET( sb->sb_sd,
+		    &iosp->ios_status.ios_osinfo.ossi_use_readfds );
+#endif /* else NSLDAPI_HAVE_POLL */
+#endif /* NSLDAPI_AVOID_OS_SOCKETS */
+
+	} else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_CALLBACK ) {
+		rc = nsldapi_find_in_cb_pollfds( sb,
+		    &iosp->ios_status.ios_cbinfo, ~LDAP_X_POLLOUT );
+
+	} else {
+		LDAPDebug( LDAP_DEBUG_ANY,
+		    "nsldapi_iostatus_is_read_ready: unknown I/O type %d\n",
+		     iosp->ios_type, 0, 0 );
+		rc = 0;
+	}
+
+unlock_and_return:
+	LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
+	return( rc );
+}
+
+
+/*
+ * Allocate and initialize ld->ld_iostatus if not already done.
+ * Should be called with LDAP_IOSTATUS_LOCK locked.
+ * Returns 0 if all goes well and -1 if not (sets error in ld)
+ */
+static int
+nsldapi_iostatus_init_nolock( LDAP *ld )
+{
+	NSLDAPIIOStatus	*iosp;
+
+	if ( ld->ld_iostatus != NULL ) {
+		return( 0 );
+	}
+
+	if (( iosp = (NSLDAPIIOStatus *)NSLDAPI_CALLOC( 1,
+	    sizeof( NSLDAPIIOStatus ))) == NULL ) {
+		LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+		return( -1 );
+	}
+
+	if ( ld->ld_extpoll_fn == NULL ) {
+		iosp->ios_type = NSLDAPI_IOSTATUS_TYPE_OSNATIVE;
+#ifdef NSLDAPI_AVOID_OS_SOCKETS
+		return( -1 );
+#else /* NSLDAPI_AVOID_OS_SOCKETS */
+#ifndef NSLDAPI_HAVE_POLL
+		FD_ZERO( &iosp->ios_status.ios_osinfo.ossi_readfds );
+		FD_ZERO( &iosp->ios_status.ios_osinfo.ossi_writefds );
+#endif /* !NSLDAPI_HAVE_POLL */
+#endif /* NSLDAPI_AVOID_OS_SOCKETS */
+
+	} else {
+		iosp->ios_type = NSLDAPI_IOSTATUS_TYPE_CALLBACK;
+	}
+
+	ld->ld_iostatus = iosp;
+	return( 0 );
+}
+
+
+void
+nsldapi_iostatus_free( LDAP *ld )
+{
+	if ( ld == NULL ) {
+		return;
+	}
+
+		
+	/* clean up classic I/O compatibility glue */
+	if ( ld->ld_io_fns_ptr != NULL ) {
+		if ( ld->ld_ext_session_arg != NULL ) {
+			NSLDAPI_FREE( ld->ld_ext_session_arg );
+		}
+		NSLDAPI_FREE( ld->ld_io_fns_ptr );
+	}
+
+	/* clean up I/O status tracking info. */
+	if ( ld->ld_iostatus != NULL ) {
+		NSLDAPIIOStatus	*iosp = ld->ld_iostatus;
+
+		if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
+#ifdef NSLDAPI_HAVE_POLL
+			if ( iosp->ios_status.ios_osinfo.ossi_pollfds
+			    != NULL ) {
+				NSLDAPI_FREE(
+				    iosp->ios_status.ios_osinfo.ossi_pollfds );
+			}
+#endif /* NSLDAPI_HAVE_POLL */
+
+		} else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_CALLBACK ) {
+			if ( iosp->ios_status.ios_cbinfo.cbsi_pollfds
+			    != NULL ) {
+				NSLDAPI_FREE(
+				    iosp->ios_status.ios_cbinfo.cbsi_pollfds );
+			}
+		} else {
+			LDAPDebug( LDAP_DEBUG_ANY,
+			    "nsldapi_iostatus_free: unknown I/O type %d\n",
+			     iosp->ios_type, 0, 0 );
+		}
+
+		NSLDAPI_FREE( iosp );
+	}
+}
+
+
+
+#if !defined(NSLDAPI_HAVE_POLL) && !defined(NSLDAPI_AVOID_OS_SOCKETS)
+static int
+nsldapi_get_select_table_size( void )
+{
+	static int	tblsize = 0;	/* static */
+
+	if ( tblsize == 0 ) {
+#if defined(_WINDOWS) || defined(XP_OS2)
+		tblsize = FOPEN_MAX; /* ANSI spec. */
+#else
+#ifdef USE_SYSCONF
+		tblsize = sysconf( _SC_OPEN_MAX );
+#else /* USE_SYSCONF */
+		tblsize = getdtablesize();
+#endif /* else USE_SYSCONF */
+#endif /* else _WINDOWS */
+
+		if ( tblsize >= FD_SETSIZE ) {
+			/*
+			 * clamp value so we don't overrun the fd_set structure
+			 */
+			tblsize = FD_SETSIZE - 1;
+		}
+	}
+
+	return( tblsize );
+}
+#endif /* !defined(NSLDAPI_HAVE_POLL) && !defined(NSLDAPI_AVOID_OS_SOCKETS) */
+
+
+static int
+nsldapi_tv2ms( struct timeval *tv )
+{
+	if ( tv == NULL ) {
+		return( -1 );	/* infinite timout for poll() */
+	}
+
+	return( tv->tv_sec * 1000 + tv->tv_usec / 1000 );
+}
+
+
+int
+nsldapi_iostatus_poll( LDAP *ld, struct timeval *timeout )
+{
+	int			rc;
+	NSLDAPIIOStatus		*iosp;
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_iostatus_poll\n", 0, 0, 0 );
+
+	LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
+	iosp = ld->ld_iostatus;
+
+	if ( iosp == NULL ||
+            ( iosp->ios_read_count <= 0 && iosp->ios_write_count <= 0 )) {
+		rc = 0;		/* simulate a timeout */
+
+	} else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
+#ifndef NSLDAPI_AVOID_OS_SOCKETS
+#ifdef NSLDAPI_HAVE_POLL
+
+		rc = NSLDAPI_POLL( iosp->ios_status.ios_osinfo.ossi_pollfds,
+		    iosp->ios_status.ios_osinfo.ossi_pollfds_size,
+		    nsldapi_tv2ms( timeout ));
+
+#else /* NSLDAPI_HAVE_POLL */
+
+		/* two (potentially large) struct copies */
+		iosp->ios_status.ios_osinfo.ossi_use_readfds
+		    = iosp->ios_status.ios_osinfo.ossi_readfds;
+		iosp->ios_status.ios_osinfo.ossi_use_writefds
+		    = iosp->ios_status.ios_osinfo.ossi_writefds;
+
+#ifdef HPUX9
+		rc = NSLDAPI_SELECT( nsldapi_get_select_table_size(),
+		    (int *)&iosp->ios_status.ios_osinfo.ossi_use_readfds
+		    (int *)&iosp->ios_status.ios_osinfo.ossi_use_writefds,
+		    NULL, timeout );
+#else
+		rc = NSLDAPI_SELECT( nsldapi_get_select_table_size(),
+		    &iosp->ios_status.ios_osinfo.ossi_use_readfds,
+		    &iosp->ios_status.ios_osinfo.ossi_use_writefds,
+		    NULL, timeout );
+#endif /* else HPUX9 */
+#endif /* else NSLDAPI_HAVE_POLL */
+#endif /* NSLDAPI_AVOID_OS_SOCKETS */
+
+	} else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_CALLBACK ) {
+		/*
+		 * We always pass the session extended I/O argument to
+		 * the extended poll() callback.
+		 */
+		rc = ld->ld_extpoll_fn( 
+		    iosp->ios_status.ios_cbinfo.cbsi_pollfds,
+		    iosp->ios_status.ios_cbinfo.cbsi_pollfds_size,
+		    nsldapi_tv2ms( timeout ), ld->ld_ext_session_arg );
+
+	} else {
+		LDAPDebug( LDAP_DEBUG_ANY,
+		    "nsldapi_iostatus_poll: unknown I/O type %d\n",
+		     iosp->ios_type, 0, 0 );
+		rc = 0;	/* simulate a timeout (what else to do?) */
+	}
+
+	LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
+	return( rc );
+}
+
+#if defined(NSLDAPI_HAVE_POLL) && !defined(NSLDAPI_AVOID_OS_SOCKETS)
+/*
+ * returns 1 if "fd" was added to pollfds.
+ * returns 1 if some of the bits in "events" were added to pollfds.
+ * returns 0 if no changes were made.
+ */
+static int
+nsldapi_add_to_os_pollfds( int fd, struct nsldapi_os_statusinfo *pip,
+	short events )
+{
+	int	i, openslot;
+
+	/* first we check to see if "fd" is already in our pollfds */
+	openslot = -1;
+	for ( i = 0; i < pip->ossi_pollfds_size; ++i ) {
+		if ( pip->ossi_pollfds[ i ].fd == fd ) {
+			if (( pip->ossi_pollfds[ i ].events & events )
+			    != events ) {
+				pip->ossi_pollfds[ i ].events |= events;
+				return( 1 );
+			} else {
+				return( 0 );
+			}
+		}
+		if ( pip->ossi_pollfds[ i ].fd == -1 && openslot == -1 ) {
+			openslot = i;	/* remember for later */
+		}
+	}
+
+	/*
+	 * "fd" is not currently being poll'd on -- add to array.
+	 * if we need to expand the pollfds array, we do it in increments of
+	 * NSLDAPI_POLL_ARRAY_GROWTH (#define near the top of this file).
+	 */
+	if ( openslot == -1 ) {
+		struct pollfd	*newpollfds;
+
+		if ( pip->ossi_pollfds_size == 0 ) {
+			newpollfds = (struct pollfd *)NSLDAPI_MALLOC(
+			    NSLDAPI_POLL_ARRAY_GROWTH
+			    * sizeof( struct pollfd ));
+		} else {
+			newpollfds = (struct pollfd *)NSLDAPI_REALLOC(
+			    pip->ossi_pollfds, (NSLDAPI_POLL_ARRAY_GROWTH
+			    + pip->ossi_pollfds_size)
+			    * sizeof( struct pollfd ));
+		}
+		if ( newpollfds == NULL ) { /* XXXmcs: no way to return err! */
+			return( 0 );
+		}
+		pip->ossi_pollfds = newpollfds;
+		openslot = pip->ossi_pollfds_size;
+		pip->ossi_pollfds_size += NSLDAPI_POLL_ARRAY_GROWTH;
+		for ( i = openslot + 1; i < pip->ossi_pollfds_size; ++i ) {
+			pip->ossi_pollfds[ i ].fd = -1;
+			pip->ossi_pollfds[ i ].events =
+			    pip->ossi_pollfds[ i ].revents = 0;
+		}
+	}
+	pip->ossi_pollfds[ openslot ].fd = fd;
+	pip->ossi_pollfds[ openslot ].events = events;
+	pip->ossi_pollfds[ openslot ].revents = 0;
+	return( 1 );
+}
+
+
+/*
+ * returns 1 if any "events" from "fd" were removed from pollfds
+ * returns 0 of "fd" wasn't in pollfds or if events did not overlap.
+ */
+static int
+nsldapi_clear_from_os_pollfds( int fd, struct nsldapi_os_statusinfo *pip,
+    short events )
+{
+	int	i;
+
+	for ( i = 0; i < pip->ossi_pollfds_size; ++i ) {
+		if ( pip->ossi_pollfds[i].fd == fd ) {
+			if (( pip->ossi_pollfds[ i ].events & events ) != 0 ) {
+				pip->ossi_pollfds[ i ].events &= ~events;
+				if ( pip->ossi_pollfds[ i ].events == 0 ) {
+					pip->ossi_pollfds[i].fd = -1;
+				}
+				return( 1 );	/* events overlap */
+			} else {
+				return( 0 );	/* events do not overlap */
+			}
+		}
+	}
+
+	return( 0 );	/* "fd" was not found */
+}
+
+
+/*
+ * returns 1 if any "revents" from "fd" were set in pollfds revents field.
+ * returns 0 if not.
+ */
+static int
+nsldapi_find_in_os_pollfds( int fd, struct nsldapi_os_statusinfo *pip,
+	short revents )
+{
+	int	i;
+
+	for ( i = 0; i < pip->ossi_pollfds_size; ++i ) {
+		if ( pip->ossi_pollfds[i].fd == fd ) {
+			if (( pip->ossi_pollfds[ i ].revents & revents ) != 0 ) {
+				return( 1 );	/* revents overlap */
+			} else {
+				return( 0 );	/* revents do not overlap */
+			}
+		}
+	}
+
+	return( 0 );	/* "fd" was not found */
+}
+#endif /* !defined(NSLDAPI_HAVE_POLL) && !defined(NSLDAPI_AVOID_OS_SOCKETS) */
+
+/*
+ * returns 1 if "sb" was added to pollfds.
+ * returns 1 if some of the bits in "events" were added to pollfds.
+ * returns 0 if no changes were made.
+ */
+static int
+nsldapi_add_to_cb_pollfds( Sockbuf *sb, struct nsldapi_cb_statusinfo *pip,
+    short events )
+{
+	int	i, openslot;
+
+	/* first we check to see if "sb" is already in our pollfds */
+	openslot = -1;
+	for ( i = 0; i < pip->cbsi_pollfds_size; ++i ) {
+		if ( NSLDAPI_CB_POLL_MATCH( sb, pip->cbsi_pollfds[ i ] )) {
+			if (( pip->cbsi_pollfds[ i ].lpoll_events & events )
+			    != events ) {
+				pip->cbsi_pollfds[ i ].lpoll_events |= events;
+				return( 1 );
+			} else {
+				return( 0 );
+			}
+		}
+		if ( pip->cbsi_pollfds[ i ].lpoll_fd == -1 && openslot == -1 ) {
+			openslot = i;	/* remember for later */
+		}
+	}
+
+	/*
+	 * "sb" is not currently being poll'd on -- add to array.
+	 * if we need to expand the pollfds array, we do it in increments of
+	 * NSLDAPI_POLL_ARRAY_GROWTH (#define near the top of this file).
+	 */
+	if ( openslot == -1 ) {
+		LDAP_X_PollFD	*newpollfds;
+
+		if ( pip->cbsi_pollfds_size == 0 ) {
+			newpollfds = (LDAP_X_PollFD *)NSLDAPI_MALLOC(
+			    NSLDAPI_POLL_ARRAY_GROWTH
+			    * sizeof( LDAP_X_PollFD ));
+		} else {
+			newpollfds = (LDAP_X_PollFD *)NSLDAPI_REALLOC(
+			    pip->cbsi_pollfds, (NSLDAPI_POLL_ARRAY_GROWTH
+			    + pip->cbsi_pollfds_size)
+			    * sizeof( LDAP_X_PollFD ));
+		}
+		if ( newpollfds == NULL ) { /* XXXmcs: no way to return err! */
+			return( 0 );
+		}
+		pip->cbsi_pollfds = newpollfds;
+		openslot = pip->cbsi_pollfds_size;
+		pip->cbsi_pollfds_size += NSLDAPI_POLL_ARRAY_GROWTH;
+		for ( i = openslot + 1; i < pip->cbsi_pollfds_size; ++i ) {
+			pip->cbsi_pollfds[ i ].lpoll_fd = -1;
+			pip->cbsi_pollfds[ i ].lpoll_socketarg = NULL;
+			pip->cbsi_pollfds[ i ].lpoll_events =
+			    pip->cbsi_pollfds[ i ].lpoll_revents = 0;
+		}
+	}
+	pip->cbsi_pollfds[ openslot ].lpoll_fd = sb->sb_sd;
+	pip->cbsi_pollfds[ openslot ].lpoll_socketarg =
+	    sb->sb_ext_io_fns.lbextiofn_socket_arg;
+	pip->cbsi_pollfds[ openslot ].lpoll_events = events;
+	pip->cbsi_pollfds[ openslot ].lpoll_revents = 0;
+	return( 1 );
+}
+
+
+/*
+ * returns 1 if any "events" from "sb" were removed from pollfds
+ * returns 0 of "sb" wasn't in pollfds or if events did not overlap.
+ */
+static int
+nsldapi_clear_from_cb_pollfds( Sockbuf *sb,
+    struct nsldapi_cb_statusinfo *pip, short events )
+{
+	int	i;
+
+	for ( i = 0; i < pip->cbsi_pollfds_size; ++i ) {
+		if ( NSLDAPI_CB_POLL_MATCH( sb, pip->cbsi_pollfds[ i ] )) {
+			if (( pip->cbsi_pollfds[ i ].lpoll_events
+			    & events ) != 0 ) {
+				pip->cbsi_pollfds[ i ].lpoll_events &= ~events;
+				if ( pip->cbsi_pollfds[ i ].lpoll_events
+				    == 0 ) {
+					pip->cbsi_pollfds[i].lpoll_fd = -1;
+				}
+				return( 1 );	/* events overlap */
+			} else {
+				return( 0 );	/* events do not overlap */
+			}
+		}
+	}
+
+	return( 0 );	/* "sb" was not found */
+}
+
+
+/*
+ * returns 1 if any "revents" from "sb" were set in pollfds revents field.
+ * returns 0 if not.
+ */
+static int
+nsldapi_find_in_cb_pollfds( Sockbuf *sb, struct nsldapi_cb_statusinfo *pip,
+    short revents )
+{
+	int	i;
+
+	for ( i = 0; i < pip->cbsi_pollfds_size; ++i ) {
+		if ( NSLDAPI_CB_POLL_MATCH( sb, pip->cbsi_pollfds[ i ] )) {
+			if (( pip->cbsi_pollfds[ i ].lpoll_revents
+			    & revents ) != 0 ) {
+				return( 1 );	/* revents overlap */
+			} else {
+				return( 0 );	/* revents do not overlap */
+			}
+		}
+	}
+
+	return( 0 );	/* "sb" was not found */
+}
+
+
+/*
+ * Install read and write functions into lber layer / sb
+ */
+int
+nsldapi_install_lber_extiofns( LDAP *ld, Sockbuf *sb )
+{
+	struct lber_x_ext_io_fns	lberiofns;
+
+	if ( NULL != sb ) {
+		lberiofns.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE;
+		lberiofns.lbextiofn_read = ld->ld_extread_fn;
+		lberiofns.lbextiofn_write = ld->ld_extwrite_fn;
+		lberiofns.lbextiofn_writev = ld->ld_extwritev_fn;
+		lberiofns.lbextiofn_socket_arg = ld->ld_ext_session_arg;
+
+		if ( ber_sockbuf_set_option( sb, LBER_SOCKBUF_OPT_EXT_IO_FNS,
+		    &lberiofns ) != 0 ) {
+			return( LDAP_LOCAL_ERROR );
+		}
+	}
+
+	return( LDAP_SUCCESS );
+}
+
+
+/*
+ ******************************************************************************
+ * One struct and several functions to bridge the gap between new extended
+ * I/O functions that are installed using ldap_set_option( ...,
+ * LDAP_OPT_EXTIO_FN_PTRS, ... ) and the original "classic" I/O functions
+ * (installed using LDAP_OPT_IO_FN_PTRS) follow.
+ *
+ * Our basic strategy is to use the new extended arg to hold a pointer to a
+ *    structure that contains a pointer to the LDAP * (which contains pointers
+ *    to the old functions so we can call them) as well as a pointer to an
+ *    LBER_SOCKET to hold the socket used by the classic functions (the new
+ *    functions use a simple int for the socket).
+ */
+typedef struct nsldapi_compat_socket_info {
+    LBER_SOCKET		csi_socket;
+    LDAP		*csi_ld;
+} NSLDAPICompatSocketInfo;
+    
+static int LDAP_CALLBACK
+nsldapi_ext_compat_read( int s, void *buf, int len,
+	struct lextiof_socket_private *arg )
+{
+	NSLDAPICompatSocketInfo	*csip = (NSLDAPICompatSocketInfo *)arg;
+	struct ldap_io_fns	*iofns = csip->csi_ld->ld_io_fns_ptr;
+
+	return( iofns->liof_read( csip->csi_socket, buf, len ));
+}
+
+
+static int LDAP_CALLBACK
+nsldapi_ext_compat_write( int s, const void *buf, int len,
+	struct lextiof_socket_private *arg  )
+{
+	NSLDAPICompatSocketInfo	*csip = (NSLDAPICompatSocketInfo *)arg;
+	struct ldap_io_fns	*iofns = csip->csi_ld->ld_io_fns_ptr;
+
+	return( iofns->liof_write( csip->csi_socket, buf, len ));
+}
+
+
+static int LDAP_CALLBACK
+nsldapi_ext_compat_poll( LDAP_X_PollFD fds[], int nfds, int timeout,
+	struct lextiof_session_private *arg )
+{
+	NSLDAPICompatSocketInfo	*csip = (NSLDAPICompatSocketInfo *)arg;
+	struct ldap_io_fns	*iofns = csip->csi_ld->ld_io_fns_ptr;
+	fd_set			readfds, writefds;
+	int			i, rc, maxfd = 0;
+	struct timeval		tv, *tvp;
+
+	/*
+	 * Prepare fd_sets for select()
+	 */
+	FD_ZERO( &readfds );
+	FD_ZERO( &writefds );
+	for ( i = 0; i < nfds; ++i ) {
+		if ( fds[ i ].lpoll_fd < 0 ) {
+			continue;
+		}
+
+		if ( fds[ i ].lpoll_fd >= FD_SETSIZE ) {
+			LDAP_SET_ERRNO( csip->csi_ld, EINVAL );
+			return( -1 );
+		}
+		
+		if ( 0 != ( fds[i].lpoll_events & LDAP_X_POLLIN )) {
+			FD_SET( fds[i].lpoll_fd, &readfds );
+		}
+
+		if ( 0 != ( fds[i].lpoll_events & LDAP_X_POLLOUT )) {
+			FD_SET( fds[i].lpoll_fd, &writefds );
+		}
+
+		fds[i].lpoll_revents = 0;	/* clear revents */
+
+		if ( fds[i].lpoll_fd >= maxfd ) {
+			maxfd = fds[i].lpoll_fd;
+		}
+	}
+
+	/*
+	 * select() using callback.
+	 */
+	++maxfd;
+	if ( timeout == -1 ) {
+		tvp = NULL;
+	} else {
+		tv.tv_sec = timeout / 1000;
+		tv.tv_usec = 1000 * ( timeout - tv.tv_sec * 1000 );
+		tvp = &tv;
+	}
+	rc = iofns->liof_select( maxfd, &readfds, &writefds, NULL, tvp );
+	if ( rc <= 0 ) {	/* timeout or fatal error */
+		return( rc );
+	}
+
+	/*
+	 * Use info. in fd_sets to populate poll() revents.
+	 */
+	for ( i = 0; i < nfds; ++i ) {
+		if ( fds[ i ].lpoll_fd < 0 ) {
+			continue;
+		}
+
+		if ( 0 != ( fds[i].lpoll_events & LDAP_X_POLLIN )
+		    && FD_ISSET( fds[i].lpoll_fd, &readfds )) {
+			fds[i].lpoll_revents |= LDAP_X_POLLIN;
+		}
+
+		if ( 0 != ( fds[i].lpoll_events & LDAP_X_POLLOUT )
+		    && FD_ISSET( fds[i].lpoll_fd, &writefds )) {
+			fds[i].lpoll_revents |= LDAP_X_POLLOUT;
+		}
+
+		/* XXXmcs: any other cases to deal with?  LDAP_X_POLLERR? */
+	}
+
+	return( rc );
+}
+
+
+static LBER_SOCKET
+nsldapi_compat_socket( LDAP *ld, int secure, int domain, int type,
+	int protocol )
+{
+	int		s;
+
+	s = ld->ld_io_fns_ptr->liof_socket( domain, type, protocol );
+
+	if ( s >= 0 ) {
+		char				*errmsg = NULL;
+
+#ifdef NSLDAPI_HAVE_POLL
+		if ( ld->ld_io_fns_ptr->liof_select != NULL
+			    && s >= FD_SETSIZE ) {
+			errmsg = "can't use socket >= FD_SETSIZE";
+		}
+#elif !defined(_WINDOWS) /* not on Windows and do not have poll() */
+		if ( s >= FD_SETSIZE ) {
+			errmsg = "can't use socket >= FD_SETSIZE";
+		}
+#endif
+
+		if ( NULL == errmsg && secure &&
+			    ld->ld_io_fns_ptr->liof_ssl_enable( s ) < 0 ) {
+			errmsg = "failed to enable secure mode";
+		    }
+
+		if ( NULL != errmsg ) {
+			if ( NULL == ld->ld_io_fns_ptr->liof_close ) {
+				nsldapi_os_closesocket( s );
+			} else {
+				ld->ld_io_fns_ptr->liof_close( s );
+			}
+			LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL,
+				    nsldapi_strdup( errmsg ));
+			return( -1 );
+		}
+	}
+
+	return( s );
+}
+
+
+/*
+ * Note: timeout is ignored because we have no way to pass it via
+ * the old I/O callback interface.
+ */
+static int LDAP_CALLBACK
+nsldapi_ext_compat_connect( const char *hostlist, int defport, int timeout,
+	unsigned long options, struct lextiof_session_private *sessionarg,
+	struct lextiof_socket_private **socketargp )
+{
+	NSLDAPICompatSocketInfo		*defcsip;
+	struct ldap_io_fns		*iofns;
+	int				s, secure;
+	NSLDAPI_SOCKET_FN		*socketfn;
+	NSLDAPI_IOCTL_FN		*ioctlfn;
+	NSLDAPI_CONNECT_WITH_TO_FN	*connectwithtofn;
+	NSLDAPI_CONNECT_FN		*connectfn;
+	NSLDAPI_CLOSE_FN		*closefn;
+
+	defcsip = (NSLDAPICompatSocketInfo *)sessionarg;
+	iofns = defcsip->csi_ld->ld_io_fns_ptr;
+
+	if ( 0 != ( options & LDAP_X_EXTIOF_OPT_SECURE )) {
+		if ( NULL == iofns->liof_ssl_enable ) {
+			LDAP_SET_ERRNO( defcsip->csi_ld, EINVAL );
+			return( -1 );
+		}
+		secure = 1;
+	} else {
+		secure = 0;
+	}
+
+	socketfn = ( iofns->liof_socket == NULL ) ?
+		    nsldapi_os_socket : nsldapi_compat_socket;
+	ioctlfn = ( iofns->liof_ioctl == NULL ) ?
+		    nsldapi_os_ioctl : (NSLDAPI_IOCTL_FN *)(iofns->liof_ioctl);
+	if ( NULL == iofns->liof_connect ) {
+		connectwithtofn = nsldapi_os_connect_with_to;
+		connectfn = NULL;
+	} else {
+		connectwithtofn = NULL;
+		connectfn = iofns->liof_connect;
+	}
+	closefn = ( iofns->liof_close == NULL ) ?
+		    nsldapi_os_closesocket : iofns->liof_close;	
+
+	s = nsldapi_try_each_host( defcsip->csi_ld, hostlist, defport,
+			secure, socketfn, ioctlfn, connectwithtofn,
+			connectfn, closefn );
+
+	if ( s >= 0 ) {
+		NSLDAPICompatSocketInfo		*csip;
+
+		if (( csip = (NSLDAPICompatSocketInfo *)NSLDAPI_CALLOC( 1,
+		    sizeof( NSLDAPICompatSocketInfo ))) == NULL ) {
+			(*closefn)( s );
+			LDAP_SET_LDERRNO( defcsip->csi_ld, LDAP_NO_MEMORY,
+				NULL, NULL );
+			return( -1 );
+		}
+
+		csip->csi_socket = s;
+		csip->csi_ld = defcsip->csi_ld;
+		*socketargp = (void *)csip;
+
+		/*
+		 * We always return 1, which is a valid but not unique socket
+		 * (file descriptor) number.  The extended I/O functions only
+		 * require that the combination of the void *arg and the int
+		 * socket be unique.  Since we allocate the
+		 * NSLDAPICompatSocketInfo that we assign to arg, we meet
+		 * that requirement.
+		 */
+		s = 1;
+	}
+
+	return( s );
+}
+
+
+static int LDAP_CALLBACK
+nsldapi_ext_compat_close( int s, struct lextiof_socket_private *arg )
+{
+	NSLDAPICompatSocketInfo	*csip = (NSLDAPICompatSocketInfo *)arg;
+	struct ldap_io_fns	*iofns = csip->csi_ld->ld_io_fns_ptr;
+	int			rc;
+
+	rc = iofns->liof_close( csip->csi_socket );
+
+	NSLDAPI_FREE( csip );
+
+	return( rc );
+}
+
+/*
+ * Install the I/O functions.
+ * Return an LDAP error code (LDAP_SUCCESS if all goes well).
+ */
+int
+nsldapi_install_compat_io_fns( LDAP *ld, struct ldap_io_fns *iofns )
+{
+	NSLDAPICompatSocketInfo		*defcsip;
+
+	if (( defcsip = (NSLDAPICompatSocketInfo *)NSLDAPI_CALLOC( 1,
+	    sizeof( NSLDAPICompatSocketInfo ))) == NULL ) {
+		return( LDAP_NO_MEMORY );
+	}
+
+	defcsip->csi_socket = -1;
+	defcsip->csi_ld = ld;
+
+	if ( ld->ld_io_fns_ptr != NULL ) {
+		(void)memset( (char *)ld->ld_io_fns_ptr, 0,
+		    sizeof( struct ldap_io_fns ));
+	} else if (( ld->ld_io_fns_ptr = (struct ldap_io_fns *)NSLDAPI_CALLOC(
+	    1, sizeof( struct ldap_io_fns ))) == NULL ) {
+		NSLDAPI_FREE( defcsip );
+		return( LDAP_NO_MEMORY );
+	}
+
+	/* struct copy */
+	*(ld->ld_io_fns_ptr) = *iofns;
+
+	ld->ld_extio_size = LBER_X_EXTIO_FNS_SIZE;
+	ld->ld_ext_session_arg = defcsip;
+	ld->ld_extread_fn = nsldapi_ext_compat_read;
+	ld->ld_extwrite_fn = nsldapi_ext_compat_write;
+	ld->ld_extpoll_fn = nsldapi_ext_compat_poll;
+	ld->ld_extconnect_fn = nsldapi_ext_compat_connect;
+	ld->ld_extclose_fn = nsldapi_ext_compat_close;
+
+	return( nsldapi_install_lber_extiofns( ld, ld->ld_sbp ));
+}
+/*
+ * end of compat I/O functions
+ ******************************************************************************
+ */
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/proxyauthctrl.c
@@ -0,0 +1,164 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+#include "ldap-int.h"
+
+/* ldap_create_proxyauth_control
+
+   Create a "version 1" proxied authorization control.
+
+   Parameters are  
+
+   ld              LDAP pointer to the desired connection 
+
+   dn		   The dn used in the proxy auth
+
+   ctl_iscritical  Indicates whether the control is critical of not. If
+                   this field is non-zero, the operation will only be car-
+                   ried out if the control is recognized by the server
+                   and/or client
+
+   ctrlp           the address of a place to put the constructed control 
+*/
+
+int
+LDAP_CALL
+ldap_create_proxyauth_control (
+     LDAP *ld, 
+     const char *dn, 
+     const char ctl_iscritical,
+     LDAPControl **ctrlp   
+)
+{
+	BerElement		*ber;
+	int				rc;
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( LDAP_PARAM_ERROR );
+	}
+
+	if (  ctrlp == NULL ) {
+		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+		return ( LDAP_PARAM_ERROR );
+	}
+	if (NULL == dn)
+	{
+	    dn = "";
+	}
+
+	/* create a ber package to hold the controlValue */
+	if ( ( nsldapi_alloc_ber_with_options( ld, &ber ) ) != LDAP_SUCCESS ) {
+		LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+		return( LDAP_NO_MEMORY );
+	}
+
+
+
+        if ( LBER_ERROR == ber_printf( ber, 
+                                       "{s}", 
+                                       dn ) ) 
+        {
+            LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
+            ber_free( ber, 1 );
+            return( LDAP_ENCODING_ERROR );
+        }
+
+	rc = nsldapi_build_control( LDAP_CONTROL_PROXYAUTH, ber, 1,
+	    ctl_iscritical, ctrlp );
+
+	LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+	return( rc );
+
+}
+
+
+/* ldap_create_proxiedauth_control
+
+   Create a "version 2" proxied authorization control.
+
+   Parameters are  
+
+   ld              LDAP pointer to the desired connection 
+
+   authzid		   The authorization identity used in the proxy auth,
+                   e.g., dn:uid=bjensen,dc=example,dc=com
+
+   ctrlp           the address of a place to put the constructed control 
+*/
+
+int
+LDAP_CALL
+ldap_create_proxiedauth_control (
+     LDAP *ld, 
+     const char *authzid, 
+     LDAPControl **ctrlp   
+)
+{
+	BerElement		*ber;
+	int				rc;
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( LDAP_PARAM_ERROR );
+	}
+
+	if (  ctrlp == NULL || authzid == NULL ) {
+		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+		return ( LDAP_PARAM_ERROR );
+	}
+
+	/* create a ber package to hold the controlValue */
+	if ( ( nsldapi_alloc_ber_with_options( ld, &ber ) ) != LDAP_SUCCESS ) {
+		LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+		return( LDAP_NO_MEMORY );
+	}
+
+
+
+        if ( LBER_ERROR == ber_printf( ber, 
+                                       "s", 
+                                       authzid ) ) 
+        {
+            LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
+            ber_free( ber, 1 );
+            return( LDAP_ENCODING_ERROR );
+        }
+
+	rc = nsldapi_build_control( LDAP_CONTROL_PROXIEDAUTH, ber, 1, 1, ctrlp );
+
+	LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+	return( rc );
+
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/psearch.c
@@ -0,0 +1,190 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ * psearch.c - Persistent search and "Entry Change Notification" support.
+ */
+#include "ldap-int.h"
+
+
+int
+LDAP_CALL
+ldap_create_persistentsearch_control( LDAP *ld, int changetypes,
+    int changesonly, int return_echg_ctls, char ctl_iscritical,
+    LDAPControl **ctrlp )
+{
+    BerElement	*ber;
+    int		rc;
+
+    if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+	return( LDAP_PARAM_ERROR );
+    }
+
+    if ( ctrlp == NULL || ( changetypes & ~LDAP_CHANGETYPE_ANY ) != 0 ) {
+	rc = LDAP_PARAM_ERROR;
+	goto report_error_and_return;
+    }
+
+    /*
+     * create a Persistent Search control.  The control value looks like this:
+     *
+     *	PersistentSearch ::= SEQUENCE {
+     *		changeTypes INTEGER,
+     *		-- the changeTypes field is the logical OR of 
+     *		-- one or more of these values: add (1), delete (2),
+     *		-- modify (4), modDN (8).  It specifies which types of
+     *		-- changes will cause an entry to be returned.
+     *		changesOnly BOOLEAN, -- skip initial search?
+     *		returnECs BOOLEAN,   -- return "Entry Change" controls?
+     *	}
+     */
+    if (( nsldapi_alloc_ber_with_options( ld, &ber )) != LDAP_SUCCESS ) {
+	rc = LDAP_NO_MEMORY;
+	goto report_error_and_return;
+    }
+
+    if ( ber_printf( ber, "{ibb}", changetypes, changesonly,
+	    return_echg_ctls ) == -1 ) {
+	ber_free( ber, 1 );
+	rc = LDAP_ENCODING_ERROR;
+	goto report_error_and_return;
+    }
+
+    rc = nsldapi_build_control( LDAP_CONTROL_PERSISTENTSEARCH, ber, 1,
+	    ctl_iscritical, ctrlp );
+
+report_error_and_return:
+    LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+    return( rc );
+}
+
+
+int
+LDAP_CALL
+ldap_parse_entrychange_control( LDAP *ld, LDAPControl **ctrls, ber_int_t *chgtypep,
+    char **prevdnp, int *chgnumpresentp, ber_int_t *chgnump )
+{
+    BerElement		*ber;
+    int				rc, i;
+    ber_int_t       changetype;
+    ber_len_t		len;
+    ber_int_t		along;
+    char			*previousdn;
+
+    if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+	return( LDAP_PARAM_ERROR );
+    }
+
+    /*
+     * find the entry change notification in the list of controls
+     */
+    for ( i = 0; ctrls != NULL && ctrls[i] != NULL; ++i ) {
+	if ( strcmp( ctrls[i]->ldctl_oid, LDAP_CONTROL_ENTRYCHANGE ) == 0 ) {
+	    break;
+	}
+    }
+
+    if ( ctrls == NULL || ctrls[i] == NULL ) {
+	rc = LDAP_CONTROL_NOT_FOUND;
+	goto report_error_and_return;
+    }
+
+    /*
+     * allocate a BER element from the control value and parse it.  The control
+     * value should look like this:
+     *
+     *	EntryChangeNotification ::= SEQUENCE {
+     *	     changeType ENUMERATED {
+     *	 	add             (1),  -- these values match the
+     *	 	delete          (2),  -- values used for changeTypes
+     *	 	modify          (4),  -- in the PersistentSearch control.
+     *	 	modDN           (8),
+     *	     },
+     *	     previousDN   LDAPDN OPTIONAL,     -- modDN ops. only
+     *	     changeNumber INTEGER OPTIONAL,    -- if supported
+     *	}
+     */
+    if (( ber = ber_init( &(ctrls[i]->ldctl_value))) == NULL ) {
+	rc = LDAP_NO_MEMORY;
+	goto report_error_and_return;
+    }		
+
+    if ( ber_scanf( ber, "{e", &along ) == LBER_ERROR ) {
+	ber_free( ber, 1 );
+	rc = LDAP_DECODING_ERROR;
+	goto report_error_and_return;
+    }
+    changetype = along;
+
+    if ( changetype == LDAP_CHANGETYPE_MODDN ) {
+	if ( ber_scanf( ber, "a", &previousdn ) == LBER_ERROR ) {
+	    ber_free( ber, 1 );
+	    rc = LDAP_DECODING_ERROR;
+	    goto report_error_and_return;
+	}
+    } else {
+	previousdn = NULL;
+    }
+
+    if ( chgtypep != NULL ) {
+	*chgtypep = changetype;
+    }
+    if ( prevdnp != NULL ) {
+	*prevdnp = previousdn;
+    } else if ( previousdn != NULL ) {
+	NSLDAPI_FREE( previousdn );
+    }
+
+    if ( chgnump != NULL ) {	/* check for optional changenumber */
+	if ( ber_peek_tag( ber, &len ) == LBER_INTEGER
+		&& ber_get_int( ber, chgnump ) != LBER_ERROR ) {
+	    if ( chgnumpresentp != NULL ) {
+		*chgnumpresentp = 1;
+	    }
+	} else {
+	    if ( chgnumpresentp != NULL ) {
+		*chgnumpresentp = 0;
+	    }
+	}
+    }
+
+    ber_free( ber, 1 );
+    rc = LDAP_SUCCESS;
+
+report_error_and_return:
+    LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+    return( rc );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/pthreadtest.c
@@ -0,0 +1,1028 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <malloc.h>
+#include <values.h>
+#include <errno.h>
+#include <pthread.h>
+#include <synch.h>
+
+#include <ldap.h>
+
+/* Authentication and search information. */
+#define NAME		"cn=Directory Manager"
+#define PASSWORD	"rtfm11111"
+#define BASE		"dc=example,dc=com"
+#define SCOPE		LDAP_SCOPE_SUBTREE
+
+static void *modify_thread();
+static void *add_thread();
+static void *delete_thread();
+static void *bind_thread();
+static void *compare_thread();
+static void *search_thread();
+static void *my_mutex_alloc();
+static void my_mutex_free();
+void *my_sema_alloc( void );
+void my_sema_free( void * );
+int my_sema_wait( void * );
+int my_sema_post( void * );
+static void set_ld_error();
+static int  get_ld_error();
+static void set_errno();
+static int  get_errno();
+static void tsd_setup();
+static void tsd_cleanup();
+static int get_random_id( void );
+static char *get_id_str( int id );
+
+/* Linked list of LDAPMessage structs for search results. */
+typedef struct ldapmsgwrapper {
+    LDAPMessage			*lmw_messagep;
+    struct ldapmsgwrapper	*lmw_next;
+} ldapmsgwrapper;
+
+LDAP		*ld;
+pthread_key_t	key;
+int		maxid = MAXINT;
+int		maxops = 0;		/* zero means no limit */
+int		range_filters = 0;	/* if non-zero use >= and >= filters */
+
+main( int argc, char **argv )
+
+{
+	pthread_attr_t			attr;
+	pthread_t			*threadids;
+	void				*status;
+	struct ldap_thread_fns		tfns;
+	struct ldap_extra_thread_fns	extrafns;
+	int		rc, c, errflg, i, inited_attr;
+	int		doadd, dodelete, domodify, docompare, dosearch, dobind;
+	int		option_extthreads, option_restart;
+	int		each_thread_count, thread_count;
+	extern int	optind;
+	extern char	*optarg;
+
+	doadd = dodelete = domodify = docompare = dobind = dosearch = 0;
+	option_extthreads = option_restart = 0;
+	inited_attr = 0;
+	errflg = 0;
+	each_thread_count = 1;	/* how many of each type of thread? */
+	rc = LDAP_SUCCESS;	/* optimistic */
+
+	while (( c = getopt( argc, argv, "abcdmrsERi:n:o:S:" )) != EOF ) {
+		switch( c ) {
+		case 'a':		/* perform add operations */
+			++doadd;
+			break;
+		case 'b':		/* perform bind operations */
+			++dobind;
+			break;
+		case 'c':		/* perform compare operations */
+			++docompare;
+			break;
+		case 'd':		/* perform delete operations */
+			++dodelete;
+			break;
+		case 'm':		/* perform modify operations */
+			++domodify;
+			break;
+		case 'r':		/* use range filters in searches */
+			++range_filters;
+			break;
+		case 's':		/* perform search operations */
+			++dosearch;
+			break;
+		case 'E':		/* use extended thread functions */
+			++option_extthreads;
+			break;
+		case 'R':		/* turn on LDAP_OPT_RESTART */
+			++option_restart;
+			break;
+		case 'i':		/* highest # used for entry names */
+			maxid = atoi( optarg );
+			break;
+		case 'n':		/* # threads for each operation */
+			if (( each_thread_count = atoi( optarg )) < 1 ) {
+				fprintf( stderr, "thread count must be > 0\n" );
+				++errflg;
+			}
+			break;
+		case 'o':		/* operations to perform per thread */
+			if (( maxops = atoi( optarg )) < 0 ) {
+				fprintf( stderr,
+				    "operation limit must be >= 0\n" );
+				++errflg;
+			}
+			break;
+		case 'S':		/* random number seed */
+			if ( *optarg == 'r' ) {
+				int	seed = (int)time( (time_t *)0 );
+				srandom( seed );
+				printf( "Random seed: %d\n", seed );
+			} else {
+				srandom( atoi( optarg ));
+			}
+			break;
+		default:
+			++errflg;
+			break;
+		}
+	}
+	
+	/* Check command-line syntax. */
+	thread_count = each_thread_count * ( doadd + dodelete + domodify
+	    + dobind + docompare + dosearch );
+	if ( thread_count < 1 ) {
+		fprintf( stderr,
+		    "Specify at least one of -a, -b, -c, -d, -m, or -s\n" );
+		++errflg;
+	}
+
+	if ( errflg || argc - optind != 2 ) {
+		fprintf( stderr, "usage: %s [-abcdmrsER] [-i id] [-n thr]"
+		    " [-o oplim] [-S sd] host port\n", argv[0] );
+		fputs( "\nWhere:\n"
+		    "\t\"id\" is the highest entry id (name) to use"
+			" (default is MAXINT)\n"
+		    "\t\"thr\" is the number of threads for each operation"
+			" (default is 1)\n"
+		    "\t\"oplim\" is the number of ops done by each thread"
+			" (default is infinite)\n"
+		    "\t\"sd\" is a random() number seed (default is 1).  Use"
+			" the letter r for\n"
+			"\t\tsd to seed random() using time of day.\n"
+		    "\t\"host\" is the hostname of an LDAP directory server\n"
+		    "\t\"port\" is the TCP port of the LDAP directory server\n"
+		    , stderr );
+		fputs( "\nAnd the single character options are:\n"
+		    "\t-a\tstart thread(s) to perform add operations\n"
+		    "\t-b\tstart thread(s) to perform bind operations\n"
+		    "\t-c\tstart thread(s) to perform compare operations\n"
+		    "\t-d\tstart thread(s) to perform delete operations\n"
+		    "\t-m\tstart thread(s) to perform modify operations\n"
+		    "\t-s\tstart thread(s) to perform search operations\n"
+		    "\t-r\tuse range filters in searches\n"
+		    "\t-E\tinstall LDAP_OPT_EXTRA_THREAD_FN_PTRS\n"
+		    "\t-R\tturn on LDAP_OPT_RESTART\n", stderr );
+
+		return( LDAP_PARAM_ERROR );
+	}
+
+	/* Create a key. */
+	if ( pthread_key_create( &key, free ) != 0 ) {
+		perror( "pthread_key_create" );
+	}
+	tsd_setup();
+
+	/* Allocate space for thread ids */
+	if (( threadids = (pthread_t *)calloc( thread_count,
+	    sizeof( pthread_t ))) == NULL ) {
+		rc = LDAP_LOCAL_ERROR;
+		goto clean_up_and_return;
+	}
+
+
+	/* Initialize the LDAP session. */
+	if (( ld = ldap_init( argv[optind], atoi( argv[optind+1] ))) == NULL ) {
+		perror( "ldap_init" );
+		rc = LDAP_LOCAL_ERROR;
+		goto clean_up_and_return;
+	}
+
+	/* Set the function pointers for dealing with mutexes
+	   and error information. */
+	memset( &tfns, '\0', sizeof(struct ldap_thread_fns) );
+	tfns.ltf_mutex_alloc = (void *(*)(void)) my_mutex_alloc;
+	tfns.ltf_mutex_free = (void (*)(void *)) my_mutex_free;
+	tfns.ltf_mutex_lock = (int (*)(void *)) pthread_mutex_lock;
+	tfns.ltf_mutex_unlock = (int (*)(void *)) pthread_mutex_unlock;
+	tfns.ltf_get_errno = get_errno;
+	tfns.ltf_set_errno = set_errno;
+	tfns.ltf_get_lderrno = get_ld_error;
+	tfns.ltf_set_lderrno = set_ld_error;
+	tfns.ltf_lderrno_arg = NULL;
+
+	/* Set up this session to use those function pointers. */
+
+	rc = ldap_set_option( ld, LDAP_OPT_THREAD_FN_PTRS, (void *) &tfns );
+	if ( rc < 0 ) {
+		rc = ldap_get_lderrno( ld, NULL, NULL );
+		fprintf( stderr,
+		    "ldap_set_option (LDAP_OPT_THREAD_FN_PTRS): %s\n",
+		    ldap_err2string( rc ) );
+		goto clean_up_and_return;
+	}
+
+	if ( option_extthreads ) {
+		/* Set the function pointers for working with semaphores. */
+
+		memset( &extrafns, '\0', sizeof(struct ldap_extra_thread_fns) );
+		extrafns.ltf_mutex_trylock =
+		    (int (*)(void *)) pthread_mutex_trylock;
+		extrafns.ltf_sema_alloc = (void *(*)(void)) my_sema_alloc;
+		extrafns.ltf_sema_free = (void (*)(void *)) my_sema_free;
+		extrafns.ltf_sema_wait = (int (*)(void *)) my_sema_wait;
+		extrafns.ltf_sema_post = (int (*)(void *)) my_sema_post;
+
+		/* Set up this session to use those function pointers. */
+
+		if ( ldap_set_option( ld, LDAP_OPT_EXTRA_THREAD_FN_PTRS,
+		    (void *) &extrafns ) != 0 ) {
+			rc = ldap_get_lderrno( ld, NULL, NULL );
+			ldap_perror( ld, "ldap_set_option"
+			    " (LDAP_OPT_EXTRA_THREAD_FN_PTRS)" );
+			goto clean_up_and_return;
+		}
+	}
+
+
+	if ( option_restart && ldap_set_option( ld, LDAP_OPT_RESTART,
+	    LDAP_OPT_ON ) != 0 ) {
+		rc = ldap_get_lderrno( ld, NULL, NULL );
+		ldap_perror( ld, "ldap_set_option(LDAP_OPT_RESTART)" );
+		goto clean_up_and_return;
+	}
+
+	/* Attempt to bind to the server. */
+	rc = ldap_simple_bind_s( ld, NAME, PASSWORD );
+	if ( rc != LDAP_SUCCESS ) {
+		fprintf( stderr, "ldap_simple_bind_s: %s\n",
+		    ldap_err2string( rc ) );
+		goto clean_up_and_return;
+	}
+
+	/* Initialize the attribute. */
+	if ( pthread_attr_init( &attr ) != 0 ) {
+		perror( "pthread_attr_init" );
+		rc = LDAP_LOCAL_ERROR;
+		goto clean_up_and_return;
+	}
+	++inited_attr;
+
+	/* Specify that the threads are joinable. */
+	pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE );
+
+	/* Create all the requested threads */
+	thread_count = 0;
+	if ( domodify ) {
+		for ( i = 0; i < each_thread_count; ++i ) {
+			if ( pthread_create( &threadids[thread_count], &attr,
+			    modify_thread, get_id_str(thread_count) ) != 0 ) {
+				perror( "pthread_create modify_thread" );
+			    rc = LDAP_LOCAL_ERROR;
+			    goto clean_up_and_return;
+			}
+			++thread_count;
+		}
+	}
+
+	if ( doadd ) {
+		for ( i = 0; i < each_thread_count; ++i ) {
+			if ( pthread_create( &threadids[thread_count], &attr,
+			    add_thread, get_id_str(thread_count) ) != 0 ) {
+				perror( "pthread_create add_thread" );
+			    rc = LDAP_LOCAL_ERROR;
+			    goto clean_up_and_return;
+			}
+			++thread_count;
+		}
+	}
+
+	if ( dodelete ) {
+		for ( i = 0; i < each_thread_count; ++i ) {
+			if ( pthread_create( &threadids[thread_count], &attr,
+			    delete_thread, get_id_str(thread_count) ) != 0 ) {
+				perror( "pthread_create delete_thread" );
+			    rc = LDAP_LOCAL_ERROR;
+			    goto clean_up_and_return;
+			}
+			++thread_count;
+		}
+	}
+
+	if ( dobind ) {
+		for ( i = 0; i < each_thread_count; ++i ) {
+			if ( pthread_create( &threadids[thread_count], &attr,
+			    bind_thread, get_id_str(thread_count) ) != 0 ) {
+				perror( "pthread_create bind_thread" );
+			    rc = LDAP_LOCAL_ERROR;
+			    goto clean_up_and_return;
+			}
+			++thread_count;
+		}
+	}
+
+	if ( docompare ) {
+		for ( i = 0; i < each_thread_count; ++i ) {
+			if ( pthread_create( &threadids[thread_count], &attr,
+			    compare_thread, get_id_str(thread_count) ) != 0 ) {
+				perror( "pthread_create compare_thread" );
+			    rc = LDAP_LOCAL_ERROR;
+			    goto clean_up_and_return;
+			}
+			++thread_count;
+		}
+	}
+
+	if ( dosearch ) {
+		for ( i = 0; i < each_thread_count; ++i ) {
+			if ( pthread_create( &threadids[thread_count], &attr,
+			    search_thread, get_id_str(thread_count) ) != 0 ) {
+				perror( "pthread_create search_thread" );
+			    rc = LDAP_LOCAL_ERROR;
+			    goto clean_up_and_return;
+			}
+			++thread_count;
+		}
+	}
+
+	/* Wait until these threads exit. */
+	for ( i = 0; i < thread_count; ++i ) {
+		pthread_join( threadids[i], &status );
+	}
+
+clean_up_and_return:
+	if ( ld != NULL ) {
+		set_ld_error( 0, NULL, NULL, NULL );  /* disposes of memory */
+		ldap_unbind( ld );
+	}
+	if ( threadids != NULL ) {
+		free( threadids );
+	}
+	if ( inited_attr ) {
+		pthread_attr_destroy( &attr );
+	}
+	tsd_cleanup();
+
+	return( rc );
+}
+
+
+static void *
+modify_thread( char *id )
+{
+	LDAPMessage	*res;
+	LDAPMessage	*e;
+	int		i, modentry, num_entries, msgid, parse_rc, finished;
+	int		rc, opcount;
+	LDAPMod		mod;
+	LDAPMod		*mods[2];
+	char		*vals[2];
+	char		*dn;
+	ldapmsgwrapper	*list, *lmwp, *lastlmwp;
+	struct timeval	zerotime;
+	void		*voidrc = (void *)0;
+
+	zerotime.tv_sec = zerotime.tv_usec = 0L;
+
+	printf( "Starting modify_thread %s.\n", id );
+	opcount = 0;
+	tsd_setup();
+
+	rc = ldap_search_ext( ld, BASE, SCOPE, "(objectclass=*)",
+		NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &msgid );
+	if ( rc != LDAP_SUCCESS ) {
+		fprintf( stderr, "Thread %s error: Modify thread: "
+		"ldap_search_ext: %s\n", id, ldap_err2string( rc ) );
+		exit( 1 );
+	}
+	list = lastlmwp = NULL;
+	finished = 0;
+	num_entries = 0;
+	while ( !finished ) {
+		rc = ldap_result( ld, msgid, LDAP_MSG_ONE, &zerotime, &res );
+		switch ( rc ) {
+		case -1:
+			rc = ldap_get_lderrno( ld, NULL, NULL );
+			fprintf( stderr, "ldap_result: %s\n", ldap_err2string( rc ) );
+			exit( 1 );
+			break;
+		case 0:
+			break;
+		/* Keep track of the number of entries found. */
+		case LDAP_RES_SEARCH_ENTRY:
+			num_entries++;
+			if (( lmwp = (ldapmsgwrapper *)
+				malloc( sizeof( ldapmsgwrapper ))) == NULL ) {
+				fprintf( stderr, "Thread %s: Modify thread: Cannot malloc\n", id );
+				exit( 1 );
+			}
+			lmwp->lmw_messagep = res;
+			lmwp->lmw_next = NULL;
+			if ( lastlmwp == NULL ) {
+				list = lastlmwp = lmwp;
+			} else {
+				lastlmwp->lmw_next = lmwp;
+			}
+			lastlmwp = lmwp;
+			break;
+		case LDAP_RES_SEARCH_REFERENCE:
+			break;
+		case LDAP_RES_SEARCH_RESULT:
+			finished = 1;
+			parse_rc = ldap_parse_result( ld, res, &rc, NULL, NULL, NULL, NULL, 1 );
+			if ( parse_rc != LDAP_SUCCESS ) {
+				fprintf( stderr, "Thread %s error: can't parse result code.\n", id );
+				exit( 1 );
+			} else {
+				if ( rc != LDAP_SUCCESS ) {
+					fprintf( stderr, "Thread %s error: ldap_search: %s\n", id, ldap_err2string( rc ) );
+				} else {
+					printf( "Thread %s: Got %d results.\n", id, num_entries );
+				}
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+	mods[0] = &mod;
+	mods[1] = NULL;
+	vals[0] = "bar";
+	vals[1] = NULL;
+
+	for ( ;; ) {
+		modentry = random() % num_entries;
+		for ( i = 0, lmwp = list; lmwp != NULL && i < modentry;
+		    i++, lmwp = lmwp->lmw_next ) {
+			/* NULL */
+		}
+
+		if ( lmwp == NULL ) {
+			fprintf( stderr,
+			    "Thread %s: Modify thread could not find entry %d of %d\n",
+			    id, modentry, num_entries );
+			continue;
+		}
+
+		e = lmwp->lmw_messagep;
+		printf( "Thread %s: Modify thread picked entry %d of %d\n", id, i, num_entries );
+		dn = ldap_get_dn( ld, e );
+
+		mod.mod_op = LDAP_MOD_REPLACE;
+		mod.mod_type = "description";
+		mod.mod_values = vals;
+		printf( "Thread %s: Modifying (%s)\n", id, dn );
+
+		rc = ldap_modify_ext_s( ld, dn, mods, NULL, NULL );
+		if ( rc != LDAP_SUCCESS ) {
+			fprintf( stderr, "ldap_modify_ext_s: %s\n",
+			    ldap_err2string( rc ) );
+			if ( rc == LDAP_SERVER_DOWN ) {
+				perror( "ldap_modify_ext_s" );
+				voidrc = (void *)1;
+				goto modify_cleanup_and_return;
+			}
+		}
+		free( dn );
+
+		++opcount;
+		if ( maxops != 0 && opcount >= maxops ) {
+			break;
+		}
+	}
+
+modify_cleanup_and_return:
+	printf( "Thread %s: attempted %d modify operations\n", id, opcount );
+	set_ld_error( 0, NULL, NULL, NULL );	/* disposes of memory */
+	tsd_cleanup();
+	free( id );
+	return voidrc;
+}
+
+
+static void *
+add_thread( char *id )
+{
+	LDAPMod	mod[4];
+	LDAPMod	*mods[5];
+	char	dn[BUFSIZ], name[40];
+	char	*cnvals[2], *snvals[2], *pwdvals[2], *ocvals[3];
+	int	i, rc, opcount;
+	void	*voidrc = (void *)0;
+
+	printf( "Starting add_thread %s.\n", id );
+	opcount = 0;
+	tsd_setup();
+
+	for ( i = 0; i < 4; i++ ) {
+		mods[i] = &mod[i];
+	}
+
+	mods[4] = NULL;
+
+	mod[0].mod_op = 0;
+	mod[0].mod_type = "cn";
+	mod[0].mod_values = cnvals;
+	cnvals[1] = NULL;
+	mod[1].mod_op = 0;
+	mod[1].mod_type = "sn";
+	mod[1].mod_values = snvals;
+	snvals[1] = NULL;
+	mod[2].mod_op = 0;
+	mod[2].mod_type = "objectclass";
+	mod[2].mod_values = ocvals;
+	ocvals[0] = "top";
+	ocvals[1] = "person";
+	ocvals[2] = NULL;
+	mod[3].mod_op = 0;
+	mod[3].mod_type = "userPassword";
+	mod[3].mod_values = pwdvals;
+	pwdvals[1] = NULL;
+	mods[4] = NULL;
+
+	for ( ;; ) {
+		sprintf( name, "%d", get_random_id() );
+		sprintf( dn, "cn=%s, " BASE, name );
+		cnvals[0] = name;
+		snvals[0] = name;
+		pwdvals[0] = name;
+
+		printf( "Thread %s: Adding entry (%s)\n", id, dn );
+		rc = ldap_add_ext_s( ld, dn, mods, NULL, NULL ); 
+		if ( rc != LDAP_SUCCESS ) {
+			fprintf( stderr, "ldap_add_ext_s: %s\n",
+			    ldap_err2string( rc ) );
+			if ( rc == LDAP_SERVER_DOWN ) {
+				perror( "ldap_add_ext_s" );
+				voidrc = (void *)1;
+				goto add_cleanup_and_return;
+			}
+		}
+
+		++opcount;
+		if ( maxops != 0 && opcount >= maxops ) {
+			break;
+		}
+	}
+
+add_cleanup_and_return:
+	printf( "Thread %s: attempted %d add operations\n", id, opcount );
+	set_ld_error( 0, NULL, NULL, NULL );	/* disposes of memory */
+	tsd_cleanup();
+	free( id );
+	return voidrc;
+}
+
+
+static void *
+delete_thread( char *id )
+{
+	LDAPMessage	*res;
+	char		dn[BUFSIZ], name[40];
+	int		num_entries, msgid, rc, parse_rc, finished, opcount;
+	struct timeval	zerotime;
+	void		*voidrc = (void *)0;
+
+	zerotime.tv_sec = zerotime.tv_usec = 0L;
+
+	printf( "Starting delete_thread %s.\n", id );
+	opcount = 0;
+	tsd_setup();
+
+	rc = ldap_search_ext( ld, BASE, SCOPE, "(objectclass=*)",
+		NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &msgid );
+	if ( rc != LDAP_SUCCESS ) {
+		fprintf( stderr, "Thread %s error: Delete thread: "
+		"ldap_search_ext: %s\n", id, ldap_err2string( rc ) );
+		exit( 1 );
+	}
+
+	finished = 0;
+	num_entries = 0;
+	while ( !finished ) {
+		rc = ldap_result( ld, msgid, LDAP_MSG_ONE, &zerotime, &res );
+		switch ( rc ) {
+		case -1:
+			rc = ldap_get_lderrno( ld, NULL, NULL );
+			fprintf( stderr, "ldap_result: %s\n", ldap_err2string( rc ) );
+			exit( 1 );
+			break;
+		case 0:
+			break;
+		/* Keep track of the number of entries found. */
+		case LDAP_RES_SEARCH_ENTRY:
+			num_entries++;
+			break;
+		case LDAP_RES_SEARCH_REFERENCE:
+			break;
+		case LDAP_RES_SEARCH_RESULT:
+			finished = 1;
+			parse_rc = ldap_parse_result( ld, res, &rc, NULL, NULL, NULL, NULL, 1 );
+			if ( parse_rc != LDAP_SUCCESS ) {
+				fprintf( stderr, "Thread %s error: can't parse result code.\n", id );
+				exit( 1 );
+			} else {
+				if ( rc != LDAP_SUCCESS ) {
+					fprintf( stderr, "Thread %s error: ldap_search: %s\n", id, ldap_err2string( rc ) );
+				} else {
+					printf( "Thread %s: Got %d results.\n", id, num_entries );
+				}
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+	for ( ;; ) {
+		sprintf( name, "%d", get_random_id() );
+		sprintf( dn, "cn=%s, " BASE, name );
+		printf( "Thread %s: Deleting entry (%s)\n", id, dn );
+
+		if (( rc = ldap_delete_ext_s( ld, dn, NULL, NULL ))
+		    != LDAP_SUCCESS ) {
+			ldap_perror( ld, "ldap_delete_ext_s" );
+			if ( rc == LDAP_SERVER_DOWN ) {
+				perror( "ldap_delete_ext_s" );
+				voidrc = (void *)1;
+				goto delete_cleanup_and_return;
+			}
+		}
+
+		++opcount;
+		if ( maxops != 0 && opcount >= maxops ) {
+			break;
+		}
+	}
+
+delete_cleanup_and_return:
+	printf( "Thread %s: attempted %d delete operations\n", id, opcount );
+	set_ld_error( 0, NULL, NULL, NULL );	/* disposes of memory */
+	tsd_cleanup();
+	free( id );
+	return voidrc;
+}
+
+
+static void *
+bind_thread( char *id )
+{
+	char		dn[BUFSIZ], name[40];
+	int		rc, opcount;
+	void		*voidrc = (void *)0;
+
+	printf( "Starting bind_thread %s.\n", id );
+	opcount = 0;
+	tsd_setup();
+
+	for ( ;; ) {
+		sprintf( name, "%d", get_random_id() );
+		sprintf( dn, "cn=%s, " BASE, name );
+		printf( "Thread %s: Binding as entry (%s)\n", id, dn );
+
+		if (( rc = ldap_simple_bind_s( ld, dn, name ))
+		    != LDAP_SUCCESS ) {
+			ldap_perror( ld, "ldap_simple_bind_s" );
+			if ( rc == LDAP_SERVER_DOWN ) {
+				perror( "ldap_simple_bind_s" );
+				voidrc = (void *)1;
+				goto bind_cleanup_and_return;
+			}
+		} else {
+			printf( "Thread %s: bound as entry (%s)\n", id, dn );
+		}
+
+		++opcount;
+		if ( maxops != 0 && opcount >= maxops ) {
+			break;
+		}
+	}
+
+bind_cleanup_and_return:
+	printf( "Thread %s: attempted %d bind operations\n", id, opcount );
+	set_ld_error( 0, NULL, NULL, NULL );	/* disposes of memory */
+	tsd_cleanup();
+	free( id );
+	return voidrc;
+}
+
+
+static void *
+compare_thread( char *id )
+{
+	char		dn[BUFSIZ], name[40], cmpval[40];
+	int		rc, randval, opcount;
+	struct berval	bv;
+	void		*voidrc = (void *)0;
+
+	printf( "Starting compare_thread %s.\n", id );
+	opcount = 0;
+	tsd_setup();
+
+	for ( ;; ) {
+		randval = get_random_id();
+		sprintf( name, "%d", randval );
+		sprintf( dn, "cn=%s, " BASE, name );
+		sprintf( cmpval, "%d", randval + random() % 3 );
+		bv.bv_val = cmpval;
+		bv.bv_len = strlen( cmpval );
+
+		printf( "Thread %s: Comparing cn in entry (%s) with %s\n",
+		    id, dn, cmpval );
+
+		rc = ldap_compare_ext_s( ld, dn, "cn", &bv, NULL, NULL );
+		switch ( rc ) {
+		case LDAP_COMPARE_TRUE:
+			printf( "Thread %s: entry (%s) contains cn %s\n",
+			    id, dn, cmpval );
+			break;
+		case LDAP_COMPARE_FALSE:
+			printf( "Thread %s: entry (%s) doesn't contain cn %s\n",
+			    id, dn, cmpval );
+			break;
+		default:
+			ldap_perror( ld, "ldap_compare_ext_s" );
+			if ( rc == LDAP_SERVER_DOWN ) {
+				perror( "ldap_compare_ext_s" );
+				voidrc = (void *)1;
+				goto compare_cleanup_and_return;
+			}
+		}
+
+		++opcount;
+		if ( maxops != 0 && opcount >= maxops ) {
+			break;
+		}
+	}
+
+compare_cleanup_and_return:
+	printf( "Thread %s: attempted %d compare operations\n", id, opcount );
+	set_ld_error( 0, NULL, NULL, NULL );	/* disposes of memory */
+	tsd_cleanup();
+	free( id );
+	return voidrc;
+}
+
+
+static void *
+search_thread( char *id )
+{
+	LDAPMessage	*res, *entry;
+	char		*dn, filter[40];
+	int		rc, opcount;
+	void		*voidrc = (void *)0;
+
+	printf( "Starting search_thread %s.\n", id );
+	opcount = 0;
+	tsd_setup();
+
+	for ( ;; ) {
+		if ( range_filters ) {
+			switch( get_random_id() % 3 ) {
+			case 0:
+				sprintf( filter, "(cn>=%d)", get_random_id());
+				break;
+			case 1:
+				sprintf( filter, "(cn<=%d)", get_random_id());
+				break;
+			case 2:
+				sprintf( filter, "(&(cn>=%d)(cn<=%d))",
+				    get_random_id(), get_random_id() );
+				break;
+			}
+		} else {
+			sprintf( filter, "cn=%d", get_random_id() );
+		}
+
+		printf( "Thread %s: Searching for entry (%s)\n", id, filter );
+
+		res = NULL;
+		if (( rc = ldap_search_ext_s( ld, BASE, SCOPE, filter, NULL, 0,
+		    NULL, NULL, NULL, 0, &res )) != LDAP_SUCCESS ) {
+			ldap_perror( ld, "ldap_search_ext_s" );
+			if ( rc == LDAP_SERVER_DOWN ) {
+				perror( "ldap_search_ext_s" );
+				voidrc = (void *)1;
+				goto search_cleanup_and_return;
+			}
+		}
+		if ( res != NULL ) {
+			entry = ldap_first_entry( ld, res );
+			if ( entry == NULL ) {
+				printf( "Thread %s: found no entries\n", id );
+			} else {
+				dn = ldap_get_dn( ld, entry );
+				printf(
+				    "Thread %s: found entry (%s); %d total\n",
+				    id, dn == NULL ? "(Null)" : dn,
+				    ldap_count_entries( ld, res ));
+				ldap_memfree( dn );
+			}
+			ldap_msgfree( res );
+		}
+
+		++opcount;
+		if ( maxops != 0 && opcount >= maxops ) {
+			break;
+		}
+	}
+
+search_cleanup_and_return:
+	printf( "Thread %s: attempted %d search operations\n", id, opcount );
+	set_ld_error( 0, NULL, NULL, NULL );	/* disposes of memory */
+	tsd_cleanup();
+	free( id );
+	return voidrc;
+}
+
+
+static void *
+my_mutex_alloc( void )
+{
+	pthread_mutex_t	*mutexp;
+
+	if ( (mutexp = malloc( sizeof(pthread_mutex_t) )) != NULL ) {
+		pthread_mutex_init( mutexp, NULL );
+	}
+	return( mutexp );
+}
+
+
+void *
+my_sema_alloc( void )
+{
+	sema_t *semptr;
+
+	if( (semptr = malloc( sizeof(sema_t) ) ) != NULL ) {
+		sema_init( semptr, 0, USYNC_THREAD, NULL );
+	}
+	return ( semptr );
+}
+
+
+static void
+my_mutex_free( void *mutexp )
+{
+	pthread_mutex_destroy( (pthread_mutex_t *) mutexp );
+	free( mutexp );
+}
+
+
+void
+my_sema_free( void *semptr )
+{
+	sema_destroy( (sema_t *) semptr );
+	free( semptr );
+}
+
+
+int
+my_sema_wait( void *semptr )
+{
+	if( semptr != NULL )
+		return( sema_wait( (sema_t *) semptr ) );
+	else
+		return( -1 );
+}
+
+
+int
+my_sema_post( void *semptr )
+{
+	if( semptr != NULL )
+		return( sema_post( (sema_t *) semptr ) );
+	else
+		return( -1 );
+}
+
+
+struct ldap_error {
+	int	le_errno;
+	char	*le_matched;
+	char	*le_errmsg;
+};
+
+
+static void
+tsd_setup()
+{
+	void	*tsd;
+	tsd = pthread_getspecific( key );
+	if ( tsd != NULL ) {
+		fprintf( stderr, "tsd non-null!\n" );
+		pthread_exit( NULL );
+	}
+
+	tsd = (void *) calloc( 1, sizeof(struct ldap_error) );
+	pthread_setspecific( key, tsd );
+}
+
+
+static void
+tsd_cleanup()
+{
+	void	*tsd;
+
+	if (( tsd = pthread_getspecific( key )) != NULL ) {
+		pthread_setspecific( key, NULL );
+		free( tsd );
+	}
+}
+
+
+static void
+set_ld_error( int err, char *matched, char *errmsg, void *dummy )
+{
+	struct ldap_error *le;
+
+	le = pthread_getspecific( key );
+
+	le->le_errno = err;
+
+	if ( le->le_matched != NULL ) {
+		ldap_memfree( le->le_matched );
+	}
+	le->le_matched = matched;
+
+	if ( le->le_errmsg != NULL ) {
+		ldap_memfree( le->le_errmsg );
+	}
+	le->le_errmsg = errmsg;
+}
+
+
+static int
+get_ld_error( char **matchedp, char **errmsgp, void *dummy )
+{
+	struct ldap_error *le;
+
+	le = pthread_getspecific( key );
+	if ( matchedp != NULL ) {
+		*matchedp = le->le_matched;
+	}
+	if ( errmsgp != NULL ) {
+		*errmsgp = le->le_errmsg;
+	}
+	return( le->le_errno );
+}
+
+
+static void
+set_errno( int err )
+{
+	errno = err;
+}
+
+
+static int
+get_errno( void )
+{
+	return( errno );
+}
+
+
+static int
+get_random_id()
+{
+	return( random() % maxid );
+}
+
+
+static char *
+get_id_str( int id )
+{
+	char	idstr[ 10 ];
+
+	sprintf( idstr, "%d", id );
+	return( strdup( idstr ));
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/pwmodext.c
@@ -0,0 +1,265 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Sun LDAP C SDK.
+ *
+ * The Initial Developer of the Original Code is Sun Microsystems, Inc.
+ *
+ * Portions created by Sun Microsystems, Inc are Copyright (C) 2005
+ * Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Contributor(s): abobrov
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ldap-int.h"
+
+/* ldap_passwd */
+int
+LDAP_CALL
+ldap_passwd (
+	LDAP          *ld, 
+	struct berval *userid,
+	struct berval *oldpasswd,
+	struct berval *newpasswd,
+	LDAPControl   **serverctrls,
+	LDAPControl   **clientctrls,
+	int           *msgidp
+	)
+{
+	int				rc;
+	BerElement		*ber = NULL;
+	struct berval   *requestdata = NULL;
+	
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+		return( LDAP_PARAM_ERROR );
+	}
+
+	requestdata = NSLDAPI_MALLOC( sizeof( struct berval ) );
+	if ( requestdata == NULL ) {
+		LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+		return( LDAP_NO_MEMORY );
+	}
+	
+	/* If the requestValue field is provided, it SHALL contain a 
+	 * PasswdModifyRequestValue with one or more fields present.
+	 */
+	if ( userid || oldpasswd || newpasswd ) {
+		if ( ( nsldapi_alloc_ber_with_options( ld, &ber ) ) 
+			 != LDAP_SUCCESS ) {
+			LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+			return( LDAP_NO_MEMORY );
+		}
+		
+		/*
+		 * PasswdModifyRequestValue ::= SEQUENCE {
+		 *	 userIdentity    [0]  OCTET STRING OPTIONAL
+		 *	 oldPasswd       [1]  OCTET STRING OPTIONAL
+		 *	 newPasswd       [2]  OCTET STRING OPTIONAL }
+		 */
+		if ( LBER_ERROR == ( ber_printf( ber, "{" ) ) ) {
+			LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
+			ber_free( ber, 1 );
+			return( LDAP_ENCODING_ERROR );
+		}
+		
+		if ( userid && userid->bv_val && userid->bv_len ) {
+			if ( LBER_ERROR == ( ber_printf( ber, "to", LDAP_TAG_PWDMOD_REQ_ID, 
+							userid->bv_val, userid->bv_len ) ) ) {
+				LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
+				ber_free( ber, 1 );
+				return( LDAP_ENCODING_ERROR );
+			}
+		}
+
+		if ( oldpasswd && oldpasswd->bv_val && oldpasswd->bv_len ) {
+			if ( LBER_ERROR == ( ber_printf( ber, "to", LDAP_TAG_PWDMOD_REQ_OLD, 
+							oldpasswd->bv_val, oldpasswd->bv_len ) ) ) {
+				LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
+				ber_free( ber, 1 );
+				return( LDAP_ENCODING_ERROR );
+			}
+		}
+
+		if ( newpasswd && newpasswd->bv_val && newpasswd->bv_len ) {
+			if ( LBER_ERROR == ( ber_printf( ber, "to", LDAP_TAG_PWDMOD_REQ_NEW, 
+							newpasswd->bv_val, newpasswd->bv_len ) ) ) {
+				LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
+				ber_free( ber, 1 );
+				return( LDAP_ENCODING_ERROR );
+			}
+		}
+		
+		if ( LBER_ERROR == ( ber_printf( ber, "}" ) ) ) {
+			LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
+			ber_free( ber, 1 );
+			return( LDAP_ENCODING_ERROR );
+		}
+		
+		/* allocate struct berval with contents of the BER encoding */
+		rc = ber_flatten( ber, &requestdata );
+		if ( rc == -1 ) {
+			LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+			ber_free( ber, 1 );
+			return( LDAP_NO_MEMORY );
+		}
+	} else {
+		requestdata = NULL;
+	}
+		
+	rc = ldap_extended_operation( ld, LDAP_EXOP_MODIFY_PASSWD, requestdata, 
+										serverctrls, clientctrls, msgidp );
+	
+	/* the ber encoding is no longer needed */
+	if ( requestdata ) {
+		ber_bvfree( requestdata );
+	}
+
+	if ( ber ) {
+		ber_free( ber, 1 );
+	}
+
+	LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+	return( rc );
+}
+
+/* ldap_parse_passwd */
+int
+LDAP_CALL
+ldap_parse_passwd ( 	
+	LDAP			*ld, 
+	LDAPMessage		*result,
+	struct berval	*genpasswd
+	)
+{	
+	int			rc;
+	char			*retoidp = NULL;
+	struct berval		*retdatap = NULL;
+	BerElement		*ber = NULL;
+	ber_len_t		len;
+	ber_tag_t		tag;
+	
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+		return( LDAP_PARAM_ERROR );
+	}	
+
+	if ( !result ) {
+		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+		return( LDAP_PARAM_ERROR );
+	}
+
+	if ( !genpasswd ) {
+		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+		return( LDAP_PARAM_ERROR );
+	}
+		
+	rc = ldap_parse_extended_result( ld, result, &retoidp, &retdatap, 0 );
+	if ( rc != LDAP_SUCCESS ) {
+		return( rc );
+	}
+	
+	rc = ldap_get_lderrno( ld, NULL, NULL );
+	if ( rc != LDAP_SUCCESS ) {
+		return( rc );
+	}
+	
+	if ( retdatap ) {
+		/* allocate a Ber element with the contents of the
+		 * berval from the response.
+		 */
+		if ( ( ber = ber_init( retdatap ) ) == NULL ) {
+			LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+			return( LDAP_NO_MEMORY );
+		}
+		
+		if ( ( tag = ber_skip_tag( ber, &len ) ) == LBER_ERROR ) {
+			LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
+			ber_free( ber, 1 );
+			ldap_memfree( retoidp );
+			return( LDAP_DECODING_ERROR );
+		}
+		
+		if ( ( ( tag = ber_peek_tag( ber, &len ) ) == LBER_ERROR ) ||
+			 tag != LDAP_TAG_PWDMOD_RES_GEN ) {
+			LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
+			ber_free( ber, 1 );
+			ldap_memfree( retoidp );
+			return( LDAP_DECODING_ERROR );
+		}
+		
+		if ( ber_scanf( ber, "o}", genpasswd ) == LBER_ERROR ) {
+			LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
+			ber_free( ber, 1 );
+			ldap_memfree( retoidp );
+			return( LDAP_DECODING_ERROR );
+		}
+		
+		/* the ber encoding is no longer needed */
+		ber_free( ber,1 );
+	}
+	
+	ldap_memfree( retoidp );
+	return( LDAP_SUCCESS );
+}
+
+/* ldap_passwd_s */
+int
+LDAP_CALL
+ldap_passwd_s ( 	
+	LDAP          *ld, 
+	struct berval *userid,
+	struct berval *oldpasswd,
+	struct berval *newpasswd,
+	struct berval *genpasswd,
+	LDAPControl   **serverctrls,
+	LDAPControl   **clientctrls
+	)
+{
+	int			rc, msgid;
+	LDAPMessage             *result = NULL;
+	
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+		return( LDAP_PARAM_ERROR );
+	}	
+
+	rc = ldap_passwd( ld, userid, oldpasswd, newpasswd, serverctrls, 
+					  clientctrls, &msgid );
+	if ( rc != LDAP_SUCCESS ) {
+		return( rc );
+	}
+	
+	rc = ldap_result( ld, msgid, LDAP_MSG_ALL, NULL, &result );
+	if ( rc == -1 ) {
+		return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+	}
+
+	rc = ldap_parse_passwd( ld, result, genpasswd );
+
+	ldap_msgfree( result );
+	return( rc );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/pwpctrl.c
@@ -0,0 +1,315 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Sun LDAP C SDK.
+ *
+ * The Initial Developer of the Original Code is Sun Microsystems, Inc.
+ *
+ * Portions created by Sun Microsystems, Inc are Copyright (C) 2005
+ * Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Contributor(s): abobrov@sun.com
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ldap-int.h"
+
+/* ldap_create_passwordpolicy_control:
+
+Parameters are  
+
+ld              LDAP pointer to the desired connection 
+
+ctrlp           the address of a place to put the constructed control 
+*/
+
+int
+LDAP_CALL
+ldap_create_passwordpolicy_control ( 	
+										LDAP *ld, 
+										LDAPControl **ctrlp   
+																	)
+{
+	int rc;
+	
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( LDAP_PARAM_ERROR );
+	}
+	
+	if ( ctrlp == NULL ) {
+		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+		return ( LDAP_PARAM_ERROR );
+	}
+	
+	rc = nsldapi_build_control( LDAP_CONTROL_PASSWD_POLICY, 
+								NULL, 0, 0, ctrlp );
+	
+	LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+	return( rc );
+}
+
+/* ldap_create_passwordpolicy_control_ext:
+
+Parameters are  
+
+ld              LDAP pointer to the desired connection 
+
+ctl_iscritical  Indicates whether the control is critical of not. If
+                this field is non-zero, the operation will only be car-
+                ried out if the control is recognized by the server
+                and/or client
+
+ctrlp           the address of a place to put the constructed control 
+*/
+
+int
+LDAP_CALL
+ldap_create_passwordpolicy_control_ext ( 	
+											LDAP *ld, 
+											const char ctl_iscritical,
+											LDAPControl **ctrlp   
+																		)
+{
+	int rc;
+	
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( LDAP_PARAM_ERROR );
+	}
+	
+	if ( ctrlp == NULL ) {
+		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+		return ( LDAP_PARAM_ERROR );
+	}
+	
+	rc = nsldapi_build_control( LDAP_CONTROL_PASSWD_POLICY, 
+								NULL, 0, ctl_iscritical, ctrlp );
+	
+	LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+	return( rc );
+}
+
+/* ldap_parse_passwordpolicy_control:
+
+Parameters are  
+
+ld              LDAP pointer to the desired connection 
+
+ctrlp           pointer to LDAPControl structure, obtained from
+				calling ldap_find_control() or by other means.  
+
+exptimep        result parameter is filled in with the number of seconds before
+                the password will expire.
+
+gracep          result parameter is filled in with the number of grace logins 
+                after the password has expired.
+
+errorcodep      result parameter is filled in with the error code of the 
+                password operation.
+*/
+
+int
+LDAP_CALL
+ldap_parse_passwordpolicy_control ( 	
+									LDAP *ld, 
+									LDAPControl *ctrlp,  
+									ber_int_t *expirep,
+									ber_int_t *gracep,
+									LDAPPasswordPolicyError *errorp
+																	)
+{
+	ber_len_t	len;
+	ber_tag_t	tag;
+	ber_int_t	pp_exp = -1;
+	ber_int_t	pp_grace = -1;
+	ber_int_t	pp_warning = -1;
+	ber_int_t	pp_err = PP_noError;
+	BerElement	*ber = NULL;
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) ) {
+	    return( LDAP_PARAM_ERROR );
+	}
+	
+	if ( ctrlp == NULL ) {
+		LDAP_SET_LDERRNO( ld, LDAP_CONTROL_NOT_FOUND, NULL, NULL );
+		return ( LDAP_CONTROL_NOT_FOUND );
+	}
+	
+	/*  allocate a Ber element with the contents of the control's struct berval */
+	if ( ( ber = ber_init( &ctrlp->ldctl_value ) ) == NULL ) {
+		LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+		return( LDAP_NO_MEMORY );
+	}
+	
+	/*
+	 * The control value should look like this:
+	 *	
+	 *	PasswordPolicyResponseValue ::= SEQUENCE {
+	 *		warning [0] CHOICE {
+	 *			timeBeforeExpiration        [0] INTEGER (0 .. maxInt),
+	 *			graceLoginsRemaining        [1] INTEGER (0 .. maxInt) } OPTIONAL
+	 *		error       [1] ENUMERATED {
+	 *			passwordExpired             (0),
+	 *			accountLocked               (1),
+	 *			changeAfterReset            (2),
+	 *			passwordModNotAllowed       (3),
+	 *			mustSupplyOldPassword       (4),
+	 *			insufficientPasswordQuality (5),
+	 *			passwordTooShort            (6),
+	 *			passwordTooYoung            (7),
+	 *			passwordInHistory           (8) } OPTIONAL }
+	 */
+
+	if ( ber_scanf( ber, "{" ) == LBER_ERROR ) {
+        LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
+        ber_free( ber, 1 );
+        return( LDAP_DECODING_ERROR );
+	}
+    
+	tag = ber_peek_tag( ber, &len );
+
+	while ( (tag != LBER_ERROR) && (tag != LBER_END_OF_SEQORSET) ) {
+		if ( tag == ( LBER_CONSTRUCTED | LBER_CLASS_CONTEXT ) ) {
+			ber_skip_tag( ber, &len );
+			if ( ber_scanf( ber, "ti", &tag, &pp_warning ) == LBER_ERROR ) {
+				LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
+				ber_free( ber, 1 );
+				return( LDAP_DECODING_ERROR );
+			}
+			if ( tag == LBER_CLASS_CONTEXT ) {
+				pp_exp = pp_warning;
+			} else if ( tag == ( LBER_CLASS_CONTEXT | 0x01 ) ) {
+				pp_grace = pp_warning;
+			}
+		} else if ( tag == ( LBER_CLASS_CONTEXT | 0x01 ) ) {
+				if ( ber_scanf( ber, "ti", &tag, &pp_err ) == LBER_ERROR ) {
+					LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
+					ber_free( ber, 1 );
+					return( LDAP_DECODING_ERROR );
+				}
+		}
+		if ( tag == LBER_DEFAULT ) {
+			LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
+			ber_free( ber, 1 );
+			return( LDAP_DECODING_ERROR );
+		}
+		tag = ber_skip_tag( ber, &len );
+	}
+
+	if (expirep) *expirep = pp_exp;
+	if (gracep) *gracep = pp_grace;
+	if (errorp) *errorp = pp_err;
+
+	/* the ber encoding is no longer needed */
+	ber_free( ber, 1 );
+	return( LDAP_SUCCESS );
+}
+
+/* ldap_parse_passwordpolicy_control_ext:
+
+Parameters are  
+
+ld              LDAP pointer to the desired connection 
+
+ctrlp           An array of controls obtained from calling  
+                ldap_parse_result on the set of results 
+                returned by the server
+
+exptimep        result parameter is filled in with the number of seconds before
+                the password will expire.
+
+gracep          result parameter is filled in with the number of grace logins 
+                after the password has expired.
+
+errorcodep      result parameter is filled in with the error code of the 
+                password operation.
+*/
+
+int
+LDAP_CALL
+ldap_parse_passwordpolicy_control_ext ( 	
+										LDAP *ld, 
+										LDAPControl **ctrlp,  
+										ber_int_t *expirep,
+										ber_int_t *gracep,
+										LDAPPasswordPolicyError *errorp
+																		)
+{
+	int i, foundPPControl;
+	LDAPControl *PPCtrlp = NULL;
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) ) {
+	    return( LDAP_PARAM_ERROR );
+	}
+	
+	/* find the control in the list of controls if it exists */
+	if ( ctrlp == NULL ) {
+		LDAP_SET_LDERRNO( ld, LDAP_CONTROL_NOT_FOUND, NULL, NULL );
+		return ( LDAP_CONTROL_NOT_FOUND );
+	} 
+	foundPPControl = 0;
+	for ( i = 0; (( ctrlp[i] != NULL ) && ( !foundPPControl )); i++ ) {
+		foundPPControl = !strcmp( ctrlp[i]->ldctl_oid, LDAP_CONTROL_PASSWD_POLICY );
+	}
+	if ( !foundPPControl ) {
+		LDAP_SET_LDERRNO( ld, LDAP_CONTROL_NOT_FOUND, NULL, NULL );
+		return ( LDAP_CONTROL_NOT_FOUND );
+	} else {
+		/* let local var point to the control */
+		PPCtrlp = ctrlp[i-1];			
+	}
+	
+	return (
+	ldap_parse_passwordpolicy_control( ld, PPCtrlp, expirep, gracep, errorp ));
+}
+
+const char *
+LDAP_CALL
+ldap_passwordpolicy_err2txt( LDAPPasswordPolicyError err )
+{
+	switch(err) {
+		case PP_passwordExpired: 
+			return "Password expired";
+		case PP_accountLocked: 
+			return "Account locked";
+		case PP_changeAfterReset: 
+			return "Password must be changed";
+		case PP_passwordModNotAllowed: 
+			return "Policy prevents password modification";
+		case PP_mustSupplyOldPassword: 
+			return "Policy requires old password in order to change password";
+		case PP_insufficientPasswordQuality: 
+			return "Password fails quality checks";
+		case PP_passwordTooShort: 
+			return "Password is too short for policy";
+		case PP_passwordTooYoung: 
+			return "Password has been changed too recently";
+		case PP_passwordInHistory: 
+			return "New password is in list of old passwords";
+		case PP_noError: 
+			return "No error";
+		default: 
+			return "Unknown error code";
+	}
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/referral.c
@@ -0,0 +1,177 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ *  referral.c - routines for handling LDAPv3 referrals and references.
+ */
+
+#include "ldap-int.h"
+
+
+LDAPMessage *
+LDAP_CALL
+ldap_first_reference( LDAP *ld, LDAPMessage *res )
+{
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) || res == NULLMSG ) {
+		return( NULLMSG );
+	}
+
+	if ( res->lm_msgtype == LDAP_RES_SEARCH_REFERENCE ) {
+		return( res );
+	}
+
+	return( ldap_next_reference( ld, res ));
+}
+
+
+LDAPMessage *
+LDAP_CALL
+ldap_next_reference( LDAP *ld, LDAPMessage *ref )
+{
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) || ref == NULLMSG ) {
+		return( NULLMSG );		/* punt */
+	}
+
+	for ( ref = ref->lm_chain; ref != NULLMSG; ref = ref->lm_chain ) {
+		if ( ref->lm_msgtype == LDAP_RES_SEARCH_REFERENCE ) {
+			return( ref );
+		}
+	}
+
+	return( NULLMSG );
+}
+
+
+int
+LDAP_CALL
+ldap_count_references( LDAP *ld, LDAPMessage *res )
+{
+	int	i;
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( -1 );
+	}
+
+	for ( i = 0; res != NULL; res = res->lm_chain ) {
+		if ( res->lm_msgtype == LDAP_RES_SEARCH_REFERENCE ) {
+			++i;
+		}
+	}
+
+	return( i );
+}
+
+
+/*
+ * returns an LDAP error code.
+ */
+int
+LDAP_CALL
+ldap_parse_reference( LDAP *ld, LDAPMessage *ref, char ***referralsp,
+    LDAPControl ***serverctrlsp, int freeit )
+{
+	int		err;
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) ||
+	    !NSLDAPI_VALID_LDAPMESSAGE_REFERENCE_POINTER( ref )) {
+		return( LDAP_PARAM_ERROR );
+	}
+
+	err = nsldapi_parse_reference( ld, ref->lm_ber, referralsp,
+		serverctrlsp );
+
+	LDAP_SET_LDERRNO( ld, err, NULL, NULL );
+
+	if ( freeit ) {
+		ldap_msgfree( ref );
+	}
+
+	return( err );
+}
+
+
+/*
+ * returns an LDAP error code indicating success or failure of parsing
+ * does NOT set any error information inside "ld"
+ */
+int
+nsldapi_parse_reference( LDAP *ld, BerElement *rber, char ***referralsp,
+    LDAPControl ***serverctrlsp )
+{
+	int		err;
+	BerElement	ber;
+	char		**refs;
+
+	/*
+	 * Parse a searchResultReference message.  These are used in LDAPv3
+	 * and beyond and look like this:
+	 *
+	 *	SearchResultReference ::= [APPLICATION 19] SEQUENCE OF LDAPURL
+	 *
+	 * all wrapped up in an LDAPMessage sequence which looks like this:
+	 *
+	 *	LDAPMessage ::= SEQUENCE {
+	 *		messageID	MessageID,
+	 *		SearchResultReference
+	 *		controls	[0] Controls OPTIONAL
+	 *	}
+	 *
+	 * ldap_result() pulls out the message id, so by the time a result
+	 * message gets here we are conveniently sitting at the start of the
+	 * SearchResultReference itself.
+	 */
+	err = LDAP_SUCCESS;	/* optimistic */
+	ber = *rber;		/* struct copy */
+
+	if ( ber_scanf( &ber, "{v", &refs ) == LBER_ERROR ) {
+	    err = LDAP_DECODING_ERROR;
+	} else if ( serverctrlsp != NULL ) {
+	    /* pull out controls (if requested and any are present) */
+	    if ( ber_scanf( &ber, "}" ) == LBER_ERROR ) {
+		err = LDAP_DECODING_ERROR;
+	    } else {
+		err = nsldapi_get_controls( &ber, serverctrlsp );
+	    }
+	}
+
+	if ( referralsp == NULL ) {
+	    ldap_value_free( refs );
+	} else {
+	    *referralsp = refs;
+	}
+
+	return( err );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/regex.c
@@ -0,0 +1,920 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+#include "ldap-int.h"
+#if defined( macintosh ) || defined( DOS ) || defined( _WINDOWS ) || defined( NEED_BSDREGEX ) || defined( XP_OS2)
+#include "regex.h"
+
+/*
+ * regex - Regular expression pattern matching  and replacement
+ *
+ * By:  Ozan S. Yigit (oz)
+ *      Dept. of Computer Science
+ *      York University
+ *
+ * These routines are the PUBLIC DOMAIN equivalents of regex
+ * routines as found in 4.nBSD UN*X, with minor extensions.
+ *
+ * These routines are derived from various implementations found
+ * in software tools books, and Conroy's grep. They are NOT derived
+ * from licensed/restricted software.
+ * For more interesting/academic/complicated implementations,
+ * see Henry Spencer's regexp routines, or GNU Emacs pattern
+ * matching module.
+ *
+ * Use the actual CCL code in the CLO
+ * section of pmatch. No need for a recursive
+ * pmatch call.
+ * 
+ * Use a bitmap table to set char bits in an
+ * 8-bit chunk.
+ * 
+ * Interfaces:
+ *      re_comp:        compile a regular expression into a NFA.
+ *
+ *			char *re_comp(s)
+ *			char *s;
+ *
+ *      re_exec:        execute the NFA to match a pattern.
+ *
+ *			int re_exec(s)
+ *			char *s;
+ *
+ *	re_modw		change re_exec's understanding of what a "word"
+ *			looks like (for \< and \>) by adding into the
+ *			hidden word-syntax table.
+ *
+ *			void re_modw(s)
+ *			char *s;
+ *
+ *      re_subs:	substitute the matched portions in a new string.
+ *
+ *			int re_subs(src, dst)
+ *			char *src;
+ *			char *dst;
+ *
+ *	re_fail:	failure routine for re_exec.
+ *
+ *			void re_fail(msg, op)
+ *			char *msg;
+ *			char op;
+ *  
+ * Regular Expressions:
+ *
+ *      [1]     char    matches itself, unless it is a special
+ *                      character (metachar): . \ [ ] * + ^ $
+ *
+ *      [2]     .       matches any character.
+ *
+ *      [3]     \       matches the character following it, except
+ *			when followed by a left or right round bracket,
+ *			a digit 1 to 9 or a left or right angle bracket. 
+ *			(see [7], [8] and [9])
+ *			It is used as an escape character for all 
+ *			other meta-characters, and itself. When used
+ *			in a set ([4]), it is treated as an ordinary
+ *			character.
+ *
+ *      [4]     [set]   matches one of the characters in the set.
+ *                      If the first character in the set is "^",
+ *                      it matches a character NOT in the set, i.e. 
+ *			complements the set. A shorthand S-E is 
+ *			used to specify a set of characters S upto 
+ *			E, inclusive. The special characters "]" and 
+ *			"-" have no special meaning if they appear 
+ *			as the first chars in the set.
+ *                      examples:        match:
+ *
+ *                              [a-z]    any lowercase alpha
+ *
+ *                              [^]-]    any char except ] and -
+ *
+ *                              [^A-Z]   any char except uppercase
+ *                                       alpha
+ *
+ *                              [a-zA-Z] any alpha
+ *
+ *      [5]     *       any regular expression form [1] to [4], followed by
+ *                      closure char (*) matches zero or more matches of
+ *                      that form.
+ *
+ *      [6]     +       same as [5], except it matches one or more.
+ *
+ *      [7]             a regular expression in the form [1] to [10], enclosed
+ *                      as \(form\) matches what form matches. The enclosure
+ *                      creates a set of tags, used for [8] and for
+ *                      pattern substution. The tagged forms are numbered
+ *			starting from 1.
+ *
+ *      [8]             a \ followed by a digit 1 to 9 matches whatever a
+ *                      previously tagged regular expression ([7]) matched.
+ *
+ *	[9]	\<	a regular expression starting with a \< construct
+ *		\>	and/or ending with a \> construct, restricts the
+ *			pattern matching to the beginning of a word, and/or
+ *			the end of a word. A word is defined to be a character
+ *			string beginning and/or ending with the characters
+ *			A-Z a-z 0-9 and _. It must also be preceded and/or
+ *			followed by any character outside those mentioned.
+ *
+ *      [10]            a composite regular expression xy where x and y
+ *                      are in the form [1] to [10] matches the longest
+ *                      match of x followed by a match for y.
+ *
+ *      [11]	^	a regular expression starting with a ^ character
+ *		$	and/or ending with a $ character, restricts the
+ *                      pattern matching to the beginning of the line,
+ *                      or the end of line. [anchors] Elsewhere in the
+ *			pattern, ^ and $ are treated as ordinary characters.
+ *
+ *
+ * Acknowledgements:
+ *
+ *	HCR's Hugh Redelmeier has been most helpful in various
+ *	stages of development. He convinced me to include BOW
+ *	and EOW constructs, originally invented by Rob Pike at
+ *	the University of Toronto.
+ *
+ * References:
+ *              Software tools			Kernighan & Plauger
+ *              Software tools in Pascal        Kernighan & Plauger
+ *              Grep [rsx-11 C dist]            David Conroy
+ *		ed - text editor		Un*x Programmer's Manual
+ *		Advanced editing on Un*x	B. W. Kernighan
+ *		RegExp routines			Henry Spencer
+ *
+ * Notes:
+ *
+ *	This implementation uses a bit-set representation for character
+ *	classes for speed and compactness. Each character is represented 
+ *	by one bit in a 128-bit block. Thus, CCL always takes a 
+ *	constant 16 bytes in the internal nfa, and re_exec does a single
+ *	bit comparison to locate the character in the set.
+ *
+ * Examples:
+ *
+ *	pattern:	foo*.*
+ *	compile:	CHR f CHR o CLO CHR o END CLO ANY END END
+ *	matches:	fo foo fooo foobar fobar foxx ...
+ *
+ *	pattern:	fo[ob]a[rz]	
+ *	compile:	CHR f CHR o CCL bitset CHR a CCL bitset END
+ *	matches:	fobar fooar fobaz fooaz
+ *
+ *	pattern:	foo\\+
+ *	compile:	CHR f CHR o CHR o CHR \ CLO CHR \ END END
+ *	matches:	foo\ foo\\ foo\\\  ...
+ *
+ *	pattern:	\(foo\)[1-3]\1	(same as foo[1-3]foo)
+ *	compile:	BOT 1 CHR f CHR o CHR o EOT 1 CCL bitset REF 1 END
+ *	matches:	foo1foo foo2foo foo3foo
+ *
+ *	pattern:	\(fo.*\)-\1
+ *	compile:	BOT 1 CHR f CHR o CLO ANY END EOT 1 CHR - REF 1 END
+ *	matches:	foo-foo fo-fo fob-fob foobar-foobar ...
+ */
+
+#define MAXNFA  1024
+#define MAXTAG  10
+
+#define OKP     1
+#define NOP     0
+
+#define CHR     1
+#define ANY     2
+#define CCL     3
+#define BOL     4
+#define EOL     5
+#define BOT     6
+#define EOT     7
+#define BOW	8
+#define EOW	9
+#define REF     10
+#define CLO     11
+
+#define END     0
+
+/*
+ * The following defines are not meant to be changeable.
+ * They are for readability only.
+ */
+#define MAXCHR	128
+#define CHRBIT	8
+#define BITBLK	MAXCHR/CHRBIT
+#define BLKIND	0170
+#define BITIND	07
+
+#define ASCIIB	0177
+
+/* Plain char, on the other hand, may be signed or unsigned; it depends on
+ * the platform and perhaps a compiler option.  A hard fact of life, in C.
+ *
+ * 6-April-1999 mcs@netscape.com: replaced CHAR with REGEXCHAR to avoid
+ *              conflicts with system types on Win32.   Changed typedef
+ *              for REGEXCHAR to always be unsigned, which seems right.
+ */
+typedef unsigned char REGEXCHAR;
+
+static int  tagstk[MAXTAG];             /* subpat tag stack..*/
+static REGEXCHAR nfa[MAXNFA];		/* automaton..       */
+static int  sta = NOP;               	/* status of lastpat */
+
+static REGEXCHAR bittab[BITBLK];	/* bit table for CCL */
+					/* pre-set bits...   */
+static REGEXCHAR bitarr[] = {1,2,4,8,16,32,64,128};
+
+static void
+chset(REGEXCHAR c)
+{
+	bittab[((c) & (unsigned)BLKIND) >> 3] |= bitarr[(c) & BITIND];
+}
+
+#define badpat(x)	(*nfa = END, x)
+#define store(x)	*mp++ = x
+ 
+char *     
+LDAP_CALL
+re_comp( const char *pat )
+{
+	register REGEXCHAR *p;          /* pattern pointer   */
+	register REGEXCHAR *mp=nfa;     /* nfa pointer       */
+	register REGEXCHAR *lp;         /* saved pointer..   */
+	register REGEXCHAR *sp=nfa;     /* another one..     */
+
+	register int tagi = 0;          /* tag stack index   */
+	register int tagc = 1;          /* actual tag count  */
+
+	register int n;
+	register REGEXCHAR mask;	/* xor mask -CCL/NCL */
+	int c1, c2;
+		
+	if (!pat || !*pat) {
+		if (sta) {
+			return 0;
+		} else {
+			return badpat("No previous regular expression");
+		}
+	}
+	sta = NOP;
+
+	for (p = (REGEXCHAR*)pat; *p; p++) {
+		lp = mp;
+		switch(*p) {
+
+		case '.':               /* match any char..  */
+			store(ANY);
+			break;
+
+		case '^':               /* match beginning.. */
+			if (p == (REGEXCHAR*)pat)
+				store(BOL);
+			else {
+				store(CHR);
+				store(*p);
+			}
+			break;
+
+		case '$':               /* match endofline.. */
+			if (!*(p+1))
+				store(EOL);
+			else {
+				store(CHR);
+				store(*p);
+			}
+			break;
+
+		case '[':               /* match char class..*/
+			store(CCL);
+
+			if (*++p == '^') {
+				mask = 0377;	
+				p++;
+			}
+			else
+				mask = 0;
+
+			if (*p == '-')		/* real dash */
+				chset(*p++);
+			if (*p == ']')		/* real brac */
+				chset(*p++);
+			while (*p && *p != ']') {
+				if (*p == '-' && *(p+1) && *(p+1) != ']') {
+					p++;
+					c1 = *(p-2) + 1;
+					c2 = *p++;
+					while (c1 <= c2)
+						chset((REGEXCHAR)c1++);
+				}
+#ifdef EXTEND
+				else if (*p == '\\' && *(p+1)) {
+					p++;
+					chset(*p++);
+				}
+#endif
+				else
+					chset(*p++);
+			}
+			if (!*p)
+				return badpat("Missing ]");
+
+			for (n = 0; n < BITBLK; bittab[n++] = (REGEXCHAR) 0)
+				store(mask ^ bittab[n]);
+	
+			break;
+
+		case '*':               /* match 0 or more.. */
+		case '+':               /* match 1 or more.. */
+			if (p == (REGEXCHAR*)pat)
+				return badpat("Empty closure");
+			lp = sp;		/* previous opcode */
+			if (*lp == CLO)		/* equivalence..   */
+				break;
+			switch(*lp) {
+
+			case BOL:
+			case BOT:
+			case EOT:
+			case BOW:
+			case EOW:
+			case REF:
+				return badpat("Illegal closure");
+			default:
+				break;
+			}
+
+			if (*p == '+')
+				for (sp = mp; lp < sp; lp++)
+					store(*lp);
+
+			store(END);
+			store(END);
+			sp = mp;
+			while (--mp > lp)
+				*mp = mp[-1];
+			store(CLO);
+			mp = sp;
+			break;
+
+		case '\\':              /* tags, backrefs .. */
+			switch(*++p) {
+
+			case '(':
+				if (tagc < MAXTAG) {
+					tagstk[++tagi] = tagc;
+					store(BOT);
+					store(tagc++);
+				}
+				else
+					return badpat("Too many \\(\\) pairs");
+				break;
+			case ')':
+				if (*sp == BOT)
+					return badpat("Null pattern inside \\(\\)");
+				if (tagi > 0) {
+					store(EOT);
+					store(tagstk[tagi--]);
+				}
+				else
+					return badpat("Unmatched \\)");
+				break;
+			case '<':
+				store(BOW);
+				break;
+			case '>':
+				if (*sp == BOW)
+					return badpat("Null pattern inside \\<\\>");
+				store(EOW);
+				break;
+			case '1':
+			case '2':
+			case '3':
+			case '4':
+			case '5':
+			case '6':
+			case '7':
+			case '8':
+			case '9':
+				n = *p-'0';
+				if (tagi > 0 && tagstk[tagi] == n)
+					return badpat("Cyclical reference");
+				if (tagc > n) {
+					store(REF);
+					store(n);
+				}
+				else
+					return badpat("Undetermined reference");
+				break;
+#ifdef EXTEND
+			case 'b':
+				store(CHR);
+				store('\b');
+				break;
+			case 'n':
+				store(CHR);
+				store('\n');
+				break;
+			case 'f':
+				store(CHR);
+				store('\f');
+				break;
+			case 'r':
+				store(CHR);
+				store('\r');
+				break;
+			case 't':
+				store(CHR);
+				store('\t');
+				break;
+#endif
+			default:
+				store(CHR);
+				store(*p);
+			}
+			break;
+
+		default :               /* an ordinary char  */
+			store(CHR);
+			store(*p);
+			break;
+		}
+		sp = lp;
+	}
+	if (tagi > 0)
+		return badpat("Unmatched \\(");
+	store(END);
+	sta = OKP;
+	return 0;
+}
+
+
+static REGEXCHAR *bol;
+static REGEXCHAR *bopat[MAXTAG];
+static REGEXCHAR *eopat[MAXTAG];
+#ifdef NEEDPROTOS
+static REGEXCHAR *pmatch( REGEXCHAR *lp, REGEXCHAR *ap );
+#else /* NEEDPROTOS */
+static REGEXCHAR *pmatch();
+#endif /* NEEDPROTOS */
+
+/*
+ * re_exec:
+ * 	execute nfa to find a match.
+ *
+ *	special cases: (nfa[0])	
+ *		BOL
+ *			Match only once, starting from the
+ *			beginning.
+ *		CHR
+ *			First locate the character without
+ *			calling pmatch, and if found, call
+ *			pmatch for the remaining string.
+ *		END
+ *			re_comp failed, poor luser did not
+ *			check for it. Fail fast.
+ *
+ *	If a match is found, bopat[0] and eopat[0] are set
+ *	to the beginning and the end of the matched fragment,
+ *	respectively.
+ *
+ */
+
+int
+LDAP_CALL
+re_exec( const char *lp )
+{
+	register REGEXCHAR c;
+	register REGEXCHAR *ep = 0;
+	register REGEXCHAR *ap = nfa;
+
+	bol = (REGEXCHAR*)lp;
+
+	bopat[0] = 0;
+	bopat[1] = 0;
+	bopat[2] = 0;
+	bopat[3] = 0;
+	bopat[4] = 0;
+	bopat[5] = 0;
+	bopat[6] = 0;
+	bopat[7] = 0;
+	bopat[8] = 0;
+	bopat[9] = 0;
+
+	switch(*ap) {
+
+	case BOL:			/* anchored: match from BOL only */
+		ep = pmatch((REGEXCHAR*)lp,ap);
+		break;
+	case CHR:			/* ordinary char: locate it fast */
+		c = *(ap+1);
+		while (*lp && *(REGEXCHAR*)lp != c)
+			lp++;
+		if (!*lp)		/* if EOS, fail, else fall thru. */
+			return 0;
+	default:			/* regular matching all the way. */
+		do {
+			if ((ep = pmatch((REGEXCHAR*)lp,ap)))
+				break;
+			lp++;
+		} while (*lp);
+
+		break;
+	case END:			/* munged automaton. fail always */
+		return 0;
+	}
+	if (!ep)
+		return 0;
+
+	bopat[0] = (REGEXCHAR*)lp;
+	eopat[0] = ep;
+	return 1;
+}
+
+/* 
+ * pmatch: internal routine for the hard part
+ *
+ * 	This code is partly snarfed from an early grep written by
+ *	David Conroy. The backref and tag stuff, and various other
+ *	innovations are by oz.
+ *
+ *	special case optimizations: (nfa[n], nfa[n+1])
+ *		CLO ANY
+ *			We KNOW .* will match everything upto the
+ *			end of line. Thus, directly go to the end of
+ *			line, without recursive pmatch calls. As in
+ *			the other closure cases, the remaining pattern
+ *			must be matched by moving backwards on the
+ *			string recursively, to find a match for xy
+ *			(x is ".*" and y is the remaining pattern)
+ *			where the match satisfies the LONGEST match for
+ *			x followed by a match for y.
+ *		CLO CHR
+ *			We can again scan the string forward for the
+ *			single char and at the point of failure, we
+ *			execute the remaining nfa recursively, same as
+ *			above.
+ *
+ *	At the end of a successful match, bopat[n] and eopat[n]
+ *	are set to the beginning and end of subpatterns matched
+ *	by tagged expressions (n = 1 to 9).	
+ *
+ */
+
+#ifndef re_fail
+extern void re_fail();
+#endif /* re_fail */
+
+/*
+ * character classification table for word boundary operators BOW
+ * and EOW. the reason for not using ctype macros is that we can
+ * let the user add into our own table. see re_modw. This table
+ * is not in the bitset form, since we may wish to extend it in the
+ * future for other character classifications. 
+ *
+ *	TRUE for 0-9 A-Z a-z _
+ */
+static char chrtyp[MAXCHR] = {
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 
+	0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 0, 0, 0, 0, 0
+	};
+
+#define HIBIT		0200
+#define inascii(x)	(0177&(x))
+#define iswordc(x) 	chrtyp[inascii(x)]
+#define isinset(x,y) 	(((y)&HIBIT)?0:((x)[((y)&BLKIND)>>3] & bitarr[(y)&BITIND]))
+
+/*
+ * skip values for CLO XXX to skip past the closure
+ */
+
+#define ANYSKIP	2 	/* [CLO] ANY END ...	     */
+#define CHRSKIP	3	/* [CLO] CHR chr END ...     */
+#define CCLSKIP 18	/* [CLO] CCL 16bytes END ... */
+
+static REGEXCHAR *
+pmatch( REGEXCHAR *lp, REGEXCHAR *ap)
+{
+	register int op, c, n;
+	register REGEXCHAR *e;		/* extra pointer for CLO */
+	register REGEXCHAR *bp;		/* beginning of subpat.. */
+	register REGEXCHAR *ep;		/* ending of subpat..	 */
+	REGEXCHAR *are;			/* to save the line ptr. */
+
+	while ((op = *ap++) != END)
+		switch(op) {
+
+		case CHR:
+			if (*lp++ != *ap++)
+				return 0;
+			break;
+		case ANY:
+			if (!*lp++)
+				return 0;
+			break;
+		case CCL:
+			c = *lp++;
+			if (!isinset(ap,c))
+				return 0;
+			ap += BITBLK;
+			break;
+		case BOL:
+			if (lp != bol)
+				return 0;
+			break;
+		case EOL:
+			if (*lp)
+				return 0;
+			break;
+		case BOT:
+			bopat[*ap++] = lp;
+			break;
+		case EOT:
+			eopat[*ap++] = lp;
+			break;
+ 		case BOW:
+			if ((lp!=bol && iswordc(lp[-1])) || !iswordc(*lp))
+				return 0;
+			break;
+		case EOW:
+			if (lp==bol || !iswordc(lp[-1]) || iswordc(*lp))
+				return 0;
+			break;
+		case REF:
+			n = *ap++;
+			bp = bopat[n];
+			ep = eopat[n];
+			while (bp < ep)
+				if (*bp++ != *lp++)
+					return 0;
+			break;
+		case CLO:
+			are = lp;
+			switch(*ap) {
+
+			case ANY:
+				while (*lp)
+					lp++;
+				n = ANYSKIP;
+				break;
+			case CHR:
+				c = *(ap+1);
+				while (*lp && c == *lp)
+					lp++;
+				n = CHRSKIP;
+				break;
+			case CCL:
+				while ((c = *lp) && isinset(ap+1,c))
+					lp++;
+				n = CCLSKIP;
+				break;
+			default:
+				re_fail("closure: bad nfa.", *ap);
+				return 0;
+			}
+
+			ap += n;
+
+			while (lp >= are) {
+				if ((e = pmatch(lp, ap)))
+					return e;
+				--lp;
+			}
+			return 0;
+		default:
+			re_fail("re_exec: bad nfa.", op);
+			return 0;
+		}
+	return lp;
+}
+
+/*
+ * re_modw:
+ *	add new characters into the word table to change re_exec's
+ *	understanding of what a word should look like. Note that we
+ *	only accept additions into the word definition.
+ *
+ *	If the string parameter is 0 or null string, the table is
+ *	reset back to the default containing A-Z a-z 0-9 _. [We use
+ *	the compact bitset representation for the default table]
+ */
+
+static REGEXCHAR deftab[16] = {	
+	0, 0, 0, 0, 0, 0, 0377, 003, 0376, 0377, 0377, 0207,  
+	0376, 0377, 0377, 007 
+}; 
+
+void
+LDAP_CALL
+re_modw( char *s )
+{
+	register int i;
+
+	if (!s || !*s) {
+		for (i = 0; i < MAXCHR; i++)
+			if (!isinset(deftab,i))
+				iswordc(i) = 0;
+	}
+	else
+		while(*s)
+			iswordc(*s++) = 1;
+}
+
+/*
+ * re_subs:
+ *	substitute the matched portions of the src in dst.
+ *
+ *	&	substitute the entire matched pattern.
+ *
+ *	\digit	substitute a subpattern, with the given	tag number.
+ *		Tags are numbered from 1 to 9. If the particular
+ *		tagged subpattern does not exist, null is substituted.
+ */
+int
+LDAP_CALL
+re_subs( char *src, char *dst)
+{
+	register char      c;
+	register int       pin;
+	register REGEXCHAR *bp;
+	register REGEXCHAR *ep;
+
+	if (!*src || !bopat[0])
+		return 0;
+
+	while ((c = *src++)) {
+		switch(c) {
+
+		case '&':
+			pin = 0;
+			break;
+
+		case '\\':
+			c = *src++;
+			if (c >= '0' && c <= '9') {
+				pin = c - '0';
+				break;
+			}
+			
+		default:
+			*dst++ = c;
+			continue;
+		}
+
+		if ((bp = bopat[pin]) && (ep = eopat[pin])) {
+			while (*bp && bp < ep)
+				*dst++ = *(char*)bp++;
+			if (bp < ep)
+				return 0;
+		}
+	}
+	*dst = (char) 0;
+	return 1;
+}
+			
+#ifdef DEBUG
+
+/* No printf or exit in 16-bit Windows */
+#if defined( _WINDOWS ) && !defined( _WIN32 )
+static int LDAP_C printf( const char* pszFormat, ...)
+{
+    char buf[1024];
+	va_list arglist;
+	va_start(arglist, pszFormat);
+    vsprintf(buf, pszFormat, arglist);
+	va_end(arglist);
+    OutputDebugString(buf);
+	return 0;
+}
+#define exit(v) return
+#endif /* 16-bit Windows */
+
+
+#ifdef REGEX_DEBUG
+
+static void nfadump( REGEXCHAR *ap);
+
+/*
+ * symbolic - produce a symbolic dump of the nfa
+ */
+void
+symbolic( char *s ) 
+{
+	printf("pattern: %s\n", s);
+	printf("nfacode:\n");
+	nfadump(nfa);
+}
+
+static void
+nfadump( REGEXCHAR *ap)
+{
+	register int n;
+
+	while (*ap != END)
+		switch(*ap++) {
+		case CLO:
+			printf("CLOSURE");
+			nfadump(ap);
+			switch(*ap) {
+			case CHR:
+				n = CHRSKIP;
+				break;
+			case ANY:
+				n = ANYSKIP;
+				break;
+			case CCL:
+				n = CCLSKIP;
+				break;
+			}
+			ap += n;
+			break;
+		case CHR:
+			printf("\tCHR %c\n",*ap++);
+			break;
+		case ANY:
+			printf("\tANY .\n");
+			break;
+		case BOL:
+			printf("\tBOL -\n");
+			break;
+		case EOL:
+			printf("\tEOL -\n");
+			break;
+		case BOT:
+			printf("BOT: %d\n",*ap++);
+			break;
+		case EOT:
+			printf("EOT: %d\n",*ap++);
+			break;
+		case BOW:
+			printf("BOW\n");
+			break;
+		case EOW:
+			printf("EOW\n");
+			break;
+		case REF:
+			printf("REF: %d\n",*ap++);
+			break;
+		case CCL:
+			printf("\tCCL [");
+			for (n = 0; n < MAXCHR; n++)
+				if (isinset(ap,(REGEXCHAR)n)) {
+					if (n < ' ')
+						printf("^%c", n ^ 0x040);
+					else
+						printf("%c", n);
+				}
+			printf("]\n");
+			ap += BITBLK;
+			break;
+		default:
+			printf("bad nfa. opcode %o\n", ap[-1]);
+			exit(1);
+			break;
+		}
+}
+#endif /* REGEX_DEBUG */
+#endif /* DEBUG */
+#endif /* macintosh or DOS or _WINDOWS or NEED_BSDREGEX */
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/rename.c
@@ -0,0 +1,265 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ *  Copyright (c) 1990 Regents of the University of Michigan.
+ *  All rights reserved.
+ */
+/*
+ *  rename.c
+ */
+
+#if 0
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+/*
+ * ldap_rename - initiate an ldap modifyDN operation. Parameters:
+ *
+ *	ld		LDAP descriptor
+ *	dn		DN of the object to modify
+ *	newrdn		RDN that will form leftmost component of entry's new name
+ *      newparent       if present, this is the Distinguished Name of the entry
+ *                      which becomes the immediate parent of the existing entry
+ *	deleteoldrdn	nonzero means to delete old rdn values from the entry
+ *                      while zero means to retain them as attributes of the entry
+ *      serverctrls     list of LDAP server controls
+ *      clientctrls     list of client controls
+ *      msgidp          this result parameter will be set to the message id of the
+ *                      request if the ldap_rename() call succeeds
+ *
+ * Example:
+ *      int rc;
+ *	rc = ldap_rename( ld, dn, newrdn, newparent, deleteoldrdn, serverctrls, clientctrls, &msgid );
+ */
+int
+LDAP_CALL
+ldap_rename( 
+	   LDAP *ld, 
+	   const char *dn, 
+	   const char *newrdn, 
+	   const char *newparent,
+	   int deleteoldrdn, 
+	   LDAPControl	**serverctrls,
+	   LDAPControl	**clientctrls,  /* not used for anything yet */
+	   int *msgidp
+)
+{
+	BerElement	*ber;
+	int		rc, err;
+
+	/*
+	 * A modify dn request looks like this:
+	 *	ModifyDNRequest ::= SEQUENCE {
+	 *		entry		LDAPDN,
+	 *		newrdn		RelativeLDAPDN,
+	 *              newparent       [0] LDAPDN OPTIONAL,
+	 *		deleteoldrdn	BOOLEAN
+	 *	}
+	 */
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_rename\n", 0, 0, 0 );
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( LDAP_PARAM_ERROR );
+	}
+	if ( NULL == newrdn) {
+		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+		return( LDAP_PARAM_ERROR );
+	}
+
+	/* only ldapv3 or higher can do a proper rename
+	 * (i.e. with non-NULL newparent and/or controls)
+	 */
+
+	if (( NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION3 )
+	    && ((newparent != NULL) || (serverctrls != NULL)
+	    || (clientctrls != NULL))) {
+		LDAP_SET_LDERRNO( ld, LDAP_NOT_SUPPORTED, NULL, NULL );
+		return( LDAP_NOT_SUPPORTED );
+	}
+
+	if ( msgidp == NULL ) {
+		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+                return( LDAP_PARAM_ERROR );
+        }
+
+	LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK );
+	*msgidp = ++ld->ld_msgid;
+        LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK );
+
+	/* see if modRDN or modDN is handled by the cache */
+ 	if ( ld->ld_cache_on ) {
+		if ( newparent == NULL && ld->ld_cache_modrdn != NULL ) {
+			LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK );
+			if ( (rc = (ld->ld_cache_modrdn)( ld, *msgidp,
+			    LDAP_REQ_MODRDN, dn, newrdn, deleteoldrdn ))
+			    != 0 ) {   
+				*msgidp = rc;
+				LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+				return( LDAP_SUCCESS );
+			}
+			LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+#if 0
+		} else if ( ld->ld_cache_rename != NULL ) {
+			LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK );
+			if ( (rc = (ld->ld_cache_rename)( ld, *msgidp,
+			    LDAP_REQ_MODDN, dn, newrdn, newparent,
+			    deleteoldrdn )) != 0 ) {   
+				*msgidp = rc;
+				return( LDAP_SUCCESS );
+			}
+			LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+#endif
+		}
+	}
+
+	/* create a message to send */
+	if (( err = nsldapi_alloc_ber_with_options( ld, &ber ))
+	    != LDAP_SUCCESS ) {
+		return( err );
+	}
+
+	/* fill it in */
+	if ( ber_printf( ber, "{it{ssb", *msgidp, LDAP_REQ_MODDN, dn,
+	    newrdn, deleteoldrdn ) == -1 ) {
+		LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
+		ber_free( ber, 1 );
+		return( LDAP_ENCODING_ERROR );
+	}
+
+	if ( newparent == NULL ) {
+		if ( ber_printf( ber, "}" ) == -1 ) {
+			LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
+			ber_free( ber, 1 );
+			return( LDAP_ENCODING_ERROR );
+		}
+	} else {
+		if ( ber_printf( ber, "ts}", LDAP_TAG_NEWSUPERIOR, newparent )
+		    == -1 ) {
+			LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
+			ber_free( ber, 1 );
+			return( LDAP_ENCODING_ERROR );
+		}
+	}
+
+	if (( rc = nsldapi_put_controls( ld, serverctrls, 1, ber ))
+	    != LDAP_SUCCESS ) {
+		ber_free( ber, 1 );
+		return( rc );
+	}
+
+	/* send the message */
+	rc = nsldapi_send_initial_request( ld, *msgidp, LDAP_REQ_MODDN,
+		(char *) dn, ber );
+	*msgidp = rc;
+	return( rc < 0 ? LDAP_GET_LDERRNO( ld, NULL, NULL ) : LDAP_SUCCESS );
+}
+
+int
+LDAP_CALL
+ldap_modrdn2( LDAP *ld, const char *dn, const char *newrdn, int deleteoldrdn )
+{
+	int             msgid;
+
+	if ( ldap_rename( ld, dn, newrdn, NULL, deleteoldrdn, NULL, NULL, &msgid ) == LDAP_SUCCESS ) {
+		return( msgid );
+	} else {
+		return( -1 );	/* error is in ld handle */
+	}
+}
+
+int
+LDAP_CALL
+ldap_modrdn( LDAP *ld, const char *dn, const char *newrdn )
+{
+	return( ldap_modrdn2( ld, dn, newrdn, 1 ) );
+}
+
+int
+LDAP_CALL
+ldap_rename_s( 
+	   LDAP *ld, 
+	   const char *dn, 
+	   const char *newrdn, 
+	   const char *newparent,
+	   int deleteoldrdn, 
+	   LDAPControl	**serverctrls,
+	   LDAPControl	**clientctrls  /* not used for anything yet */
+)
+{
+	int		msgid;
+	LDAPMessage	*res;
+
+	if ( ldap_rename( ld, dn, newrdn, newparent, deleteoldrdn, serverctrls, clientctrls, &msgid ) != LDAP_SUCCESS ) {
+		return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+	}
+
+ 	if ( msgid == -1 ) 
+		return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+
+	if ( ldap_result( ld, msgid, 1, (struct timeval *) NULL, &res ) == -1 )
+		return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+
+	return( ldap_result2error( ld, res, 1 ) );
+}
+
+int
+LDAP_CALL
+ldap_modrdn2_s( LDAP *ld, const char *dn, const char *newrdn, int deleteoldrdn )
+{
+        int             msgid;
+        LDAPMessage     *res;
+ 
+        if ( (msgid = ldap_modrdn2( ld, dn, newrdn, deleteoldrdn )) == -1 )
+                return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+ 
+        if ( ldap_result( ld, msgid, 1, (struct timeval *) NULL, &res ) == -1 )
+                return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+ 
+        return( ldap_result2error( ld, res, 1 ) );
+}
+
+int
+LDAP_CALL
+ldap_modrdn_s( LDAP *ld, const char *dn, const char *newrdn )
+{
+	return( ldap_modrdn2_s( ld, dn, newrdn, 1 ) );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/request.c
@@ -0,0 +1,1659 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ *  Copyright (c) 1995 Regents of the University of Michigan.
+ *  All rights reserved.
+ */
+/*
+ *  request.c - sending of ldap requests; handling of referrals
+ */
+
+#if 0
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1995 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+static LDAPConn *find_connection( LDAP *ld, LDAPServer *srv, int any );
+static void free_servers( LDAPServer *srvlist );
+static int chase_one_referral( LDAP *ld, LDAPRequest *lr, LDAPRequest *origreq,
+    char *refurl, char *desc, int *unknownp, int is_reference );
+static int re_encode_request( LDAP *ld, BerElement *origber,
+    int msgid, LDAPURLDesc *ludp, BerElement **berp, int is_reference );
+
+#ifdef LDAP_DNS
+static LDAPServer *dn2servers( LDAP *ld, char *dn );
+#endif /* LDAP_DNS */
+
+
+/* returns an LDAP error code and also sets error inside LDAP * */
+int
+nsldapi_alloc_ber_with_options( LDAP *ld, BerElement **berp )
+{
+	int	err;
+
+	LDAP_MUTEX_LOCK( ld, LDAP_OPTION_LOCK );
+    	if (( *berp = ber_alloc_t( ld->ld_lberoptions )) == NULLBER ) {
+		err = LDAP_NO_MEMORY;
+		LDAP_SET_LDERRNO( ld, err, NULL, NULL );
+	} else {
+		err = LDAP_SUCCESS;
+#ifdef STR_TRANSLATION
+		nsldapi_set_ber_options( ld, *berp );
+#endif /* STR_TRANSLATION */
+	}
+	LDAP_MUTEX_UNLOCK( ld, LDAP_OPTION_LOCK );
+
+	return( err );
+}
+
+
+void
+nsldapi_set_ber_options( LDAP *ld, BerElement *ber )
+{
+	ber->ber_options = ld->ld_lberoptions;
+#ifdef STR_TRANSLATION
+	if (( ld->ld_lberoptions & LBER_OPT_TRANSLATE_STRINGS ) != 0 ) {
+		ber_set_string_translators( ber,
+		    ld->ld_lber_encode_translate_proc,
+		    ld->ld_lber_decode_translate_proc );
+	}
+#endif /* STR_TRANSLATION */
+}
+
+
+/* returns the message id of the request or -1 if an error occurs */
+int
+nsldapi_send_initial_request( LDAP *ld, int msgid, unsigned long msgtype,
+	char *dn, BerElement *ber )
+{
+	LDAPServer	*servers;
+	
+	LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_send_initial_request\n", 0,0,0 );
+
+#ifdef LDAP_DNS
+	LDAP_MUTEX_LOCK( ld, LDAP_OPTION_LOCK );
+	if (( ld->ld_options & LDAP_BITOPT_DNS ) != 0 && ldap_is_dns_dn( dn )) {
+		if (( servers = dn2servers( ld, dn )) == NULL ) {
+			ber_free( ber, 1 );
+			LDAP_MUTEX_UNLOCK( ld, LDAP_OPTION_LOCK );
+			return( -1 );
+		}
+
+#ifdef LDAP_DEBUG
+		if ( ldap_debug & LDAP_DEBUG_TRACE ) {
+			LDAPServer	*srv;
+			char    msg[256];
+
+			for ( srv = servers; srv != NULL;
+			    srv = srv->lsrv_next ) {
+				sprintf( msg,
+				    "LDAP server %s:  dn %s, port %d\n",
+				    srv->lsrv_host, ( srv->lsrv_dn == NULL ) ?
+				    "(default)" : srv->lsrv_dn,
+				    srv->lsrv_port );
+				ber_err_print( msg );
+			}
+		}
+#endif /* LDAP_DEBUG */
+	} else {
+#endif /* LDAP_DNS */
+		/*
+		 * use of DNS is turned off or this is an LDAP DN...
+		 * use our default connection
+		 */
+		servers = NULL;
+#ifdef LDAP_DNS
+	}	
+	LDAP_MUTEX_UNLOCK( ld, LDAP_OPTION_LOCK );
+#endif /* LDAP_DNS */
+
+	return( nsldapi_send_server_request( ld, ber, msgid, NULL,
+	    servers, NULL, ( msgtype == LDAP_REQ_BIND ) ? dn : NULL, 0 ));
+}
+
+
+/* returns the message id of the request or -1 if an error occurs */
+int
+nsldapi_send_server_request(
+    LDAP *ld,			/* session handle */
+    BerElement *ber,		/* message to send */
+    int msgid,			/* ID of message to send */
+    LDAPRequest *parentreq,	/* non-NULL for referred requests */
+    LDAPServer *srvlist,	/* servers to connect to (NULL for default) */
+    LDAPConn *lc,		/* connection to use (NULL for default) */
+    char *bindreqdn,		/* non-NULL for bind requests */
+    int bind			/* perform a bind after opening new conn.? */
+)
+{
+	LDAPRequest	*lr;
+	int		err;
+	int		incparent; /* did we bump parent's ref count? */
+	/* EPIPE and Unsolicited Response handling variables */
+	int				res_rc     = 0;
+	int				epipe_err  = 0;
+	int				ext_res_rc = 0;
+	char			*ext_oid   = NULL;
+	struct berval	*ext_data  = NULL;
+	LDAPMessage		*ext_res   = NULL;
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_send_server_request\n", 0, 0, 0 );
+
+	incparent = 0;
+	LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK );
+	if ( lc == NULL ) {
+		if ( srvlist == NULL ) {
+			if ( ld->ld_defconn == NULL ) {
+				LDAP_MUTEX_LOCK( ld, LDAP_OPTION_LOCK );
+				if ( bindreqdn == NULL && ( ld->ld_options
+				    & LDAP_BITOPT_RECONNECT ) != 0 ) {
+					LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN,
+					    NULL, NULL );
+					ber_free( ber, 1 );
+					LDAP_MUTEX_UNLOCK( ld, LDAP_OPTION_LOCK );
+					LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
+					return( -1 );
+				}
+				LDAP_MUTEX_UNLOCK( ld, LDAP_OPTION_LOCK );
+
+				if ( nsldapi_open_ldap_defconn( ld ) < 0 ) {
+					ber_free( ber, 1 );
+					LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
+					return( -1 );
+				}
+			}
+			lc = ld->ld_defconn;
+		} else {
+			if (( lc = find_connection( ld, srvlist, 1 )) ==
+			    NULL ) {
+				if ( bind && (parentreq != NULL) ) {
+					/* Remember the bind in the parent */
+					incparent = 1;
+					++parentreq->lr_outrefcnt;
+				}
+
+				lc = nsldapi_new_connection( ld, &srvlist, 0,
+					1, bind );
+			}
+			free_servers( srvlist );
+		}
+	}
+
+
+	/*
+     * return a fatal error if:
+     * 1. no connections exists
+	 * or 
+     * 2. the connection is dead
+	 * or 
+     * 3. it is not in the connected state with normal (non async) I/O
+	 */
+	if (   lc == NULL
+                    || ( lc->lconn_status == LDAP_CONNST_DEAD )
+                    || ( 0 == (ld->ld_options & LDAP_BITOPT_ASYNC) &&
+                        lc->lconn_status != LDAP_CONNST_CONNECTED) ) {
+
+		ber_free( ber, 1 );
+		if ( lc != NULL ) {
+			LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN, NULL, NULL );
+		}
+		if ( incparent ) {
+			/* Forget about the bind */
+			--parentreq->lr_outrefcnt; 
+		}
+		LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
+		return( -1 );
+	}
+
+	if (( lr = nsldapi_new_request( lc, ber, msgid,
+	    1 /* expect a response */)) == NULL
+	    || ( bindreqdn != NULL && ( bindreqdn =
+	    nsldapi_strdup( bindreqdn )) == NULL )) {
+		if ( lr != NULL ) {
+			NSLDAPI_FREE( lr );
+		}
+		LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+		nsldapi_free_connection( ld, lc, NULL, NULL, 0, 0 );
+		ber_free( ber, 1 );
+		if ( incparent ) {
+			/* Forget about the bind */
+			--parentreq->lr_outrefcnt; 
+		}
+		LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
+		return( -1 );
+	} 
+	lr->lr_binddn = bindreqdn;
+
+	if ( parentreq != NULL ) {	/* sub-request */
+		if ( !incparent ) { 
+			/* Increment if we didn't do it before the bind */
+			++parentreq->lr_outrefcnt;
+		}
+		lr->lr_origid = parentreq->lr_origid;
+		lr->lr_parentcnt = parentreq->lr_parentcnt + 1;
+		lr->lr_parent = parentreq;
+		if ( parentreq->lr_child != NULL ) {
+			lr->lr_sibling = parentreq->lr_child;
+		}
+		parentreq->lr_child = lr;
+	} else {			/* original request */
+		lr->lr_origid = lr->lr_msgid;
+	}
+
+	LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
+        /* add new request to the end of the list of outstanding requests */
+	nsldapi_queue_request_nolock( ld, lr );
+
+	/*
+	 * Issue a non-blocking poll() if we need to check this
+	 * connection's status.
+	 */
+	if ( lc->lconn_status == LDAP_CONNST_CONNECTING ||
+	    lc->lconn_pending_requests > 0 ) {
+		struct timeval	tv;
+
+		tv.tv_sec = tv.tv_usec = 0;
+		(void)nsldapi_iostatus_poll( ld, &tv );
+	}
+
+	/*
+	 * If the connect is pending, check to see if it has now completed.
+	 */
+	if ( lc->lconn_status == LDAP_CONNST_CONNECTING &&
+	    nsldapi_iostatus_is_write_ready( ld, lc->lconn_sb )) {
+		lc->lconn_status = LDAP_CONNST_CONNECTED;
+
+		LDAPDebug( LDAP_DEBUG_TRACE,
+		    "nsldapi_send_server_request: connection 0x%p -"
+		    " LDAP_CONNST_CONNECTING -> LDAP_CONNST_CONNECTED\n",
+		    lc, 0, 0 );
+	}
+
+    if ( lc->lconn_status == LDAP_CONNST_CONNECTING ||
+                        lc->lconn_pending_requests > 0 ) {
+       /*
+        * The connect is not yet complete, or there are existing
+        * requests that have not yet been sent to the server.
+        * Delay sending this request.
+        */
+		lr->lr_status = LDAP_REQST_WRITING;
+                ++lc->lconn_pending_requests;
+		nsldapi_iostatus_interest_write( ld, lc->lconn_sb );
+
+		/*
+		 * If the connection is now connected, and it is ready
+		 * to accept some more outbound data, send as many
+		 * pending requests as possible.
+		 */
+		if ( lc->lconn_status != LDAP_CONNST_CONNECTING
+		    && nsldapi_iostatus_is_write_ready( ld, lc->lconn_sb )) {
+			if ( nsldapi_send_pending_requests_nolock( ld, lc )
+			    == -1 ) {	/* error */
+				/*
+				 * Since nsldapi_send_pending_requests_nolock()
+				 * sets LDAP errno, there is no need to do so
+				 * here.
+				 */
+				LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
+				LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
+				return( -1 );
+			}
+		}
+
+	    } else {
+		    if (( err = nsldapi_send_ber_message( ld, lc->lconn_sb,
+				    ber, 0 /* do not free ber */, 
+				    1 /* will handle EPIPE */ )) != 0 ) {
+				    
+				epipe_err = LDAP_GET_ERRNO( ld );
+				if ( epipe_err == EPIPE ) {
+					res_rc = nsldapi_result_nolock(ld, LDAP_RES_UNSOLICITED, 1, 
+									1, (struct timeval *) NULL, &ext_res);
+					if ( ( res_rc == LDAP_RES_EXTENDED ) && ext_res ) {
+						ext_res_rc = ldap_parse_extended_result( ld, ext_res, 
+										&ext_oid, &ext_data, 0 );
+						if ( ext_res_rc != LDAP_SUCCESS ) {
+							if ( ext_res ) {
+								ldap_msgfree( ext_res );
+							}					
+							nsldapi_connection_lost_nolock( ld, lc->lconn_sb );
+						} else {
+#ifdef LDAP_DEBUG
+	LDAPDebug( LDAP_DEBUG_TRACE, 
+			   "nsldapi_send_server_request: Unsolicited response\n", 0, 0, 0 );
+	if ( ext_oid ) {
+		LDAPDebug( LDAP_DEBUG_TRACE, 
+				"nsldapi_send_server_request: Unsolicited response oid: %s\n", 
+				   ext_oid, 0, 0 );
+	}
+	if ( ext_data && ext_data->bv_len && ext_data->bv_val ) {
+		LDAPDebug( LDAP_DEBUG_TRACE, 
+				"nsldapi_send_server_request: Unsolicited response len: %d\n", 
+				   ext_data->bv_len, 0, 0 );
+		LDAPDebug( LDAP_DEBUG_TRACE, 
+				"nsldapi_send_server_request: Unsolicited response val: %s\n", 
+				   ext_data->bv_val, 0, 0 );
+	}
+	if ( !ext_oid && !ext_data ) { 					
+		LDAPDebug( LDAP_DEBUG_TRACE, 
+				"nsldapi_send_server_request: Unsolicited response is empty\n", 
+				   0, 0, 0 );
+	}
+#endif /* LDAP_DEBUG */
+							if ( ext_oid ) {
+								if ( strcmp ( ext_oid, 
+										LDAP_NOTICE_OF_DISCONNECTION ) == 0 ) {
+									if ( ext_data ) {
+										ber_bvfree( ext_data );
+									}
+									if ( ext_oid ) {
+										ldap_memfree( ext_oid );
+									}
+									if ( ext_res ) {
+										ldap_msgfree( ext_res );
+									}
+									nsldapi_connection_lost_nolock( ld, 
+														lc->lconn_sb );
+									nsldapi_free_request( ld, lr, 0 );
+									nsldapi_free_connection( ld, lc, 
+													NULL, NULL, 0, 0 );
+									LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
+									LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
+									return( -1 );					
+								}
+							}
+						}
+					} else {
+						if ( ext_res ) {
+							ldap_msgfree( ext_res );
+						}				
+						nsldapi_connection_lost_nolock( ld, lc->lconn_sb );
+					}
+				}
+
+                /* need to continue write later */
+                if (err == -2 ) {       
+                   	lr->lr_status = LDAP_REQST_WRITING;
+                   	++lc->lconn_pending_requests;
+                   	nsldapi_iostatus_interest_write( ld, lc->lconn_sb );
+                } else {
+					LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN, NULL, NULL );
+					nsldapi_free_request( ld, lr, 0 );
+                    nsldapi_free_connection( ld, lc, NULL, NULL, 0, 0 );
+					LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
+					LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
+					return( -1 );
+				}
+
+			} else {
+				if ( parentreq == NULL ) {
+					ber->ber_end = ber->ber_ptr;
+					ber->ber_ptr = ber->ber_buf;
+				}
+
+				/* sent -- waiting for a response */
+				if (ld->ld_options & LDAP_BITOPT_ASYNC) {
+					lc->lconn_status = LDAP_CONNST_CONNECTED;
+				}
+
+				nsldapi_iostatus_interest_read( ld, lc->lconn_sb );
+			}
+	}
+	LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
+	LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
+
+	LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL );
+	return( msgid );
+}
+
+
+/*
+ * nsldapi_send_ber_message(): Attempt to send a BER-encoded message.
+ * If freeit is non-zero, ber is freed when the send succeeds.
+ * If errno is EPIPE and epipe_handler is set we let the caller
+ * deal with EPIPE and dont call lost_nolock here but the caller 
+ * should call lost_nolock itself when done with handling EPIPE.
+ *
+ * Return values:
+ *    0: message sent successfully.
+ *   -1: a fatal error occurred while trying to send.
+ *   -2: async. I/O is enabled and the send would block.
+ */
+int
+nsldapi_send_ber_message( LDAP *ld, Sockbuf *sb, BerElement *ber, int freeit,
+		int epipe_handler )
+{
+	int	rc = 0;	/* optimistic */
+	int	async = ( 0 != (ld->ld_options & LDAP_BITOPT_ASYNC));
+	int	more_to_send = 1;
+
+	while ( more_to_send) {
+		 /*
+		  * ber_flush() doesn't set errno on EOF, so we pre-set it to
+		  * zero to avoid getting tricked by leftover "EAGAIN" errors
+		  */
+		LDAP_SET_ERRNO( ld, 0 );
+
+		if ( ber_flush( sb, ber, freeit ) == 0 ) {
+			more_to_send = 0;	/* success */
+		} else {
+			int terrno = LDAP_GET_ERRNO( ld );
+			if ( NSLDAPI_ERRNO_IO_INPROGRESS( terrno )) {
+				if ( async ) {
+					rc = -2;
+					break;
+				}
+			} else {
+				if ( !(epipe_handler && ( terrno == EPIPE )) ) {
+					nsldapi_connection_lost_nolock( ld, sb );
+				}
+				rc = -1;	/* fatal error */
+				break;
+			}
+		}
+    }
+
+	return( rc );
+}
+
+
+/*
+ * nsldapi_send_pending_requests_nolock(): Send one or more pending requests
+ * that are associated with connection 'lc'.
+ *
+ * Return values:  0 -- success.
+ *		  -1 -- fatal error; connection closed.
+ *
+ * Must be called with these two mutexes locked, in this order:
+ *	LDAP_CONN_LOCK
+ *	LDAP_REQ_LOCK
+ */
+int
+nsldapi_send_pending_requests_nolock( LDAP *ld, LDAPConn *lc )
+{
+	int		err;
+	int		waiting_for_a_response = 0;
+	int		rc = 0;
+	LDAPRequest	*lr;
+	char		*logname = "nsldapi_send_pending_requests_nolock";
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "%s\n", logname, 0, 0 );
+
+	for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) {
+		/*
+		 * This code relies on the fact that the ld_requests list
+		 * is in order from oldest to newest request (the oldest
+		 * requests that have not yet been sent to the server are
+		 * sent first).
+		 */
+		if ( lr->lr_status == LDAP_REQST_WRITING
+		    && lr->lr_conn == lc ) {
+			err = nsldapi_send_ber_message( ld, lc->lconn_sb,
+			    lr->lr_ber, 0 /* do not free ber */, 
+			    0 /* will not handle EPIPE */ );
+			if ( err == 0 ) {		/* send succeeded */
+				LDAPDebug( LDAP_DEBUG_TRACE,
+				    "%s: 0x%p SENT\n", logname, lr, 0 );
+				lr->lr_ber->ber_end = lr->lr_ber->ber_ptr;
+				lr->lr_ber->ber_ptr = lr->lr_ber->ber_buf;
+				lr->lr_status = LDAP_REQST_INPROGRESS;
+				--lc->lconn_pending_requests;
+			} else if ( err == -2 ) {	/* would block */
+				rc = 0; /* not an error */
+				LDAPDebug( LDAP_DEBUG_TRACE,
+				    "%s: 0x%p WOULD BLOCK\n", logname, lr, 0 );
+				break;
+			} else {			/* fatal error */
+				LDAPDebug( LDAP_DEBUG_TRACE,
+				    "%s: 0x%p FATAL ERROR\n", logname, lr, 0 );
+				LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN,
+				    NULL, NULL );
+				nsldapi_free_request( ld, lr, 0 );
+				lr = NULL;
+				nsldapi_free_connection( ld, lc, NULL, NULL,
+				    0, 0 );
+				lc = NULL;
+				rc = -1;
+				break;
+			}
+		}
+
+		if (lr->lr_status == LDAP_REQST_INPROGRESS ) {
+			if (lr->lr_expect_resp) {
+				++waiting_for_a_response;
+			} else {
+				LDAPDebug( LDAP_DEBUG_TRACE,
+				    "%s: 0x%p NO RESPONSE EXPECTED;"
+				    " freeing request \n", logname, lr, 0 );
+				nsldapi_free_request( ld, lr, 0 );
+				lr = NULL;
+			}
+		}
+	}
+
+	if ( lc != NULL ) {
+		if ( lc->lconn_pending_requests < 1 ) {
+			/* no need to poll for "write ready" any longer */
+			nsldapi_iostatus_interest_clear( ld, lc->lconn_sb );
+		}
+
+		if ( waiting_for_a_response ) {
+			/* need to poll for "read ready" */
+			nsldapi_iostatus_interest_read( ld, lc->lconn_sb );
+		}
+	}
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "%s <- %d\n", logname, rc, 0 );
+	return( rc );
+}
+
+
+LDAPConn *
+nsldapi_new_connection( LDAP *ld, LDAPServer **srvlistp, int use_ldsb,
+	int connect, int bind )
+{
+	int		rc = -1;
+	LDAPConn	*lc;
+	LDAPServer	*prevsrv, *srv;
+	Sockbuf		*sb = NULL;
+
+	/*
+	 * make a new LDAP server connection
+	 */
+	if (( lc = (LDAPConn *)NSLDAPI_CALLOC( 1, sizeof( LDAPConn ))) == NULL
+	    || ( !use_ldsb && ( sb = ber_sockbuf_alloc()) == NULL )) {
+		if ( lc != NULL ) {
+			NSLDAPI_FREE( (char *)lc );
+		}
+		LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+		return( NULL );
+	}
+
+	LDAP_MUTEX_LOCK( ld, LDAP_OPTION_LOCK );
+	if ( !use_ldsb ) {
+		/*
+		 * we have allocated a new sockbuf
+		 * set I/O routines to match those in default LDAP sockbuf
+		 */
+		IFP				sb_fn;
+		struct lber_x_ext_io_fns	extiofns;
+		
+		extiofns.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE;
+
+		if ( ber_sockbuf_get_option( ld->ld_sbp,
+		    LBER_SOCKBUF_OPT_EXT_IO_FNS, &extiofns ) == 0 ) {
+			ber_sockbuf_set_option( sb,
+			    LBER_SOCKBUF_OPT_EXT_IO_FNS, &extiofns );
+		}
+		if ( ber_sockbuf_get_option( ld->ld_sbp,
+		    LBER_SOCKBUF_OPT_READ_FN, (void *)&sb_fn ) == 0
+		    && sb_fn != NULL ) {
+			ber_sockbuf_set_option( sb, LBER_SOCKBUF_OPT_READ_FN,
+			    (void *)sb_fn );
+		}
+		if ( ber_sockbuf_get_option( ld->ld_sbp,
+		    LBER_SOCKBUF_OPT_WRITE_FN, (void *)&sb_fn ) == 0
+		    && sb_fn != NULL ) {
+			ber_sockbuf_set_option( sb, LBER_SOCKBUF_OPT_WRITE_FN,
+			    (void *)sb_fn );
+		}
+	}
+
+	lc->lconn_sb = ( use_ldsb ) ? ld->ld_sbp : sb;
+	lc->lconn_version = ld->ld_version;	/* inherited */
+	LDAP_MUTEX_UNLOCK( ld, LDAP_OPTION_LOCK );
+
+	if ( connect ) {
+		prevsrv = NULL;
+        /* 
+         * save the return code for later
+         */ 
+		for ( srv = *srvlistp; srv != NULL; srv = srv->lsrv_next ) {
+			rc = nsldapi_connect_to_host( ld, lc->lconn_sb,
+				   srv->lsrv_host, srv->lsrv_port,
+			       (  srv->lsrv_options & LDAP_SRV_OPT_SECURE ) != 0,
+					&lc->lconn_krbinstance );
+			if (rc != -1) {
+				break;
+			}
+			prevsrv = srv;
+		}
+
+		if ( srv == NULL ) {
+		    if ( !use_ldsb ) {
+			NSLDAPI_FREE( (char *)lc->lconn_sb );
+		    }
+		    NSLDAPI_FREE( (char *)lc );
+		    /* nsldapi_open_ldap_connection has already set ld_errno */
+		    return( NULL );
+		}
+
+		if ( prevsrv == NULL ) {
+		    *srvlistp = srv->lsrv_next;
+		} else {
+		    prevsrv->lsrv_next = srv->lsrv_next;
+		}
+		lc->lconn_server = srv;
+	}
+
+        if ( 0 != (ld->ld_options & LDAP_BITOPT_ASYNC)) {
+                /*
+                 * Technically, the socket may already be connected but we are
+                 * not sure. By setting the state to LDAP_CONNST_CONNECTING, we
+                 * ensure that we will check the socket status to make sure it
+                 * is connected before we try to send any LDAP messages.
+                 */
+        lc->lconn_status = LDAP_CONNST_CONNECTING;
+    } else {
+        lc->lconn_status = LDAP_CONNST_CONNECTED;
+    }
+    
+	lc->lconn_next = ld->ld_conns;
+	ld->ld_conns = lc;
+
+	/*
+	 * XXX for now, we always do a synchronous bind.  This will have
+	 * to change in the long run...
+	 */
+	if ( bind ) {
+		int		err, lderr, freepasswd, authmethod;
+		char		*binddn, *passwd;
+		LDAPConn	*savedefconn;
+
+		freepasswd = err = 0;
+
+		if ( ld->ld_rebind_fn == NULL ) {
+			binddn = passwd = "";
+			authmethod = LDAP_AUTH_SIMPLE;
+		} else {
+			if (( lderr = (*ld->ld_rebind_fn)( ld, &binddn, &passwd,
+			    &authmethod, 0, ld->ld_rebind_arg ))
+			    == LDAP_SUCCESS ) {
+				freepasswd = 1;
+			} else {
+				LDAP_SET_LDERRNO( ld, lderr, NULL, NULL );
+				err = -1;
+			}
+		}
+
+
+		if ( err == 0 ) {
+			savedefconn = ld->ld_defconn;
+			ld->ld_defconn = lc;
+			++lc->lconn_refcnt;	/* avoid premature free */
+
+			/*
+			 * when binding, we will back down as low as LDAPv2
+			 * if we get back "protocol error" from bind attempts
+			 */
+			for ( ;; ) {
+				/* LDAP_MUTEX_UNLOCK(ld, LDAP_CONN_LOCK); */
+				if (( lderr = ldap_bind_s( ld, binddn, passwd,
+				    authmethod )) == LDAP_SUCCESS ) {
+					/* LDAP_MUTEX_LOCK(ld, LDAP_CONN_LOCK); */
+					break;
+				}
+				/* LDAP_MUTEX_LOCK(ld, LDAP_CONN_LOCK); */
+				if ( lc->lconn_version <= LDAP_VERSION2
+				    || lderr != LDAP_PROTOCOL_ERROR ) {
+					err = -1;
+					break;
+				}
+				--lc->lconn_version;	/* try lower version */
+			}
+			--lc->lconn_refcnt;
+			ld->ld_defconn = savedefconn;
+		}
+
+		if ( freepasswd ) {
+			(*ld->ld_rebind_fn)( ld, &binddn, &passwd,
+				&authmethod, 1, ld->ld_rebind_arg );
+		}
+
+		if ( err != 0 ) {
+			nsldapi_free_connection( ld, lc, NULL, NULL, 1, 0 );
+			lc = NULL;
+		}
+	}
+
+	return( lc );
+}
+
+
+#define LDAP_CONN_SAMEHOST( h1, h2 ) \
+	(( (h1) == NULL && (h2) == NULL ) || \
+	( (h1) != NULL && (h2) != NULL && strcasecmp( (h1), (h2) ) == 0 ))
+
+static LDAPConn *
+find_connection( LDAP *ld, LDAPServer *srv, int any )
+/*
+ * return an existing connection (if any) to the server srv
+ * if "any" is non-zero, check for any server in the "srv" chain
+ */
+{
+	LDAPConn	*lc;
+	LDAPServer	*ls;
+
+	for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
+		for ( ls = srv; ls != NULL; ls = ls->lsrv_next ) {
+			if ( LDAP_CONN_SAMEHOST( ls->lsrv_host,
+			    lc->lconn_server->lsrv_host )
+			    && ls->lsrv_port == lc->lconn_server->lsrv_port
+			    && ls->lsrv_options ==
+			    lc->lconn_server->lsrv_options ) {
+				return( lc );
+			}
+			if ( !any ) {
+				break;
+			}
+		}
+	}
+
+	return( NULL );
+}
+
+
+void
+nsldapi_free_connection( LDAP *ld, LDAPConn *lc, LDAPControl **serverctrls,
+    LDAPControl **clientctrls, int force, int unbind )
+{
+	LDAPConn	*tmplc, *prevlc;
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_free_connection\n", 0, 0, 0 );
+
+	if ( force || --lc->lconn_refcnt <= 0 ) {
+		nsldapi_iostatus_interest_clear( ld, lc->lconn_sb );
+		if ( lc->lconn_status == LDAP_CONNST_CONNECTED ) {
+			if ( unbind ) {
+				nsldapi_send_unbind( ld, lc->lconn_sb,
+				    serverctrls, clientctrls );
+			}
+		}
+		nsldapi_close_connection( ld, lc->lconn_sb );
+		prevlc = NULL;
+		for ( tmplc = ld->ld_conns; tmplc != NULL;
+		    tmplc = tmplc->lconn_next ) {
+			if ( tmplc == lc ) {
+				if ( prevlc == NULL ) {
+				    ld->ld_conns = tmplc->lconn_next;
+				} else {
+				    prevlc->lconn_next = tmplc->lconn_next;
+				}
+				break;
+			}
+			prevlc = tmplc;
+		}
+		free_servers( lc->lconn_server );
+		if ( lc->lconn_krbinstance != NULL ) {
+			NSLDAPI_FREE( lc->lconn_krbinstance );
+		}
+		/*
+		 * if this is the default connection (lc->lconn_sb==ld->ld_sbp)
+		 * we do not free the Sockbuf here since it will be freed
+		 * later inside ldap_unbind().
+		 */
+		if ( lc->lconn_sb != ld->ld_sbp ) {
+			ber_sockbuf_free( lc->lconn_sb );
+			lc->lconn_sb = NULL;
+		}
+		if ( lc->lconn_ber != NULLBER ) {
+			ber_free( lc->lconn_ber, 1 );
+		}
+		if ( lc->lconn_binddn != NULL ) {
+			NSLDAPI_FREE( lc->lconn_binddn );
+		}
+#ifdef LDAP_SASLIO_HOOKS
+		if ( lc->lconn_sasl_ctx ) { /* the sasl connection context */
+			sasl_dispose(&lc->lconn_sasl_ctx);
+			lc->lconn_sasl_ctx = NULL;
+		}
+#endif /* LDAP_SASLIO_HOOKS */
+		NSLDAPI_FREE( lc );
+		LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_free_connection: actually freed\n",
+		    0, 0, 0 );
+	} else {
+		lc->lconn_lastused = time( 0 );
+		LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_free_connection: refcnt %d\n",
+		    lc->lconn_refcnt, 0, 0 );
+	}
+}
+
+
+#ifdef LDAP_DEBUG
+void
+nsldapi_dump_connection( LDAP *ld, LDAPConn *lconns, int all )
+{
+	LDAPConn	*lc;
+	char        msg[256];
+/* CTIME for this platform doesn't use this. */
+#if !defined(SUNOS4) && !defined(_WIN32) && !defined(LINUX) && !defined(macintosh)
+	char		buf[26];
+#endif
+
+	sprintf( msg, "** Connection%s:\n", all ? "s" : "" );
+	ber_err_print( msg );
+	for ( lc = lconns; lc != NULL; lc = lc->lconn_next ) {
+		if ( lc->lconn_server != NULL ) {
+                        sprintf( msg, "* 0x%p - host: %s  port: %d  secure: %s%s\n",
+                                lc, ( lc->lconn_server->lsrv_host == NULL ) ? "(null)"
+			    : lc->lconn_server->lsrv_host,
+			    lc->lconn_server->lsrv_port,
+			    ( lc->lconn_server->lsrv_options &
+			    LDAP_SRV_OPT_SECURE ) ? "Yes" :
+			    "No", ( lc->lconn_sb == ld->ld_sbp ) ?
+			    "  (default)" : "" );
+			ber_err_print( msg );
+		}
+                sprintf( msg, "  refcnt: %d  pending: %d  status: %s\n",
+                    lc->lconn_refcnt, lc->lconn_pending_requests,
+                    ( lc->lconn_status == LDAP_CONNST_CONNECTING )
+                    ? "Connecting" :
+		    ( lc->lconn_status == LDAP_CONNST_DEAD ) ? "Dead" :
+		    "Connected" );
+		ber_err_print( msg );
+		sprintf( msg, "  last used: %s",
+		    NSLDAPI_CTIME( (time_t *) &lc->lconn_lastused, buf,
+				sizeof(buf) ));
+		ber_err_print( msg );
+		if ( lc->lconn_ber != NULLBER ) {
+			ber_err_print( "  partial response has been received:\n" );
+			ber_dump( lc->lconn_ber, 1 );
+		}
+		ber_err_print( "\n" );
+
+		if ( !all ) {
+			break;
+		}
+	}
+}
+
+
+void
+nsldapi_dump_requests_and_responses( LDAP *ld )
+{
+	LDAPRequest	*lr;
+	LDAPMessage	*lm, *l;
+	char        msg[256];
+
+	ber_err_print( "** Outstanding Requests:\n" );
+	LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
+	if (( lr = ld->ld_requests ) == NULL ) {
+		ber_err_print( "   Empty\n" );
+	}
+	for ( ; lr != NULL; lr = lr->lr_next ) {
+            sprintf( msg, " * 0x%p - msgid %d,  origid %d, status %s\n",
+                lr, lr->lr_msgid, lr->lr_origid, ( lr->lr_status ==
+		LDAP_REQST_INPROGRESS ) ? "InProgress" :
+		( lr->lr_status == LDAP_REQST_CHASINGREFS ) ? "ChasingRefs" :
+		( lr->lr_status == LDAP_REQST_CONNDEAD ) ? "Dead" :
+		"Writing" );
+	    ber_err_print( msg );
+	    sprintf( msg, "   outstanding referrals %d, parent count %d\n",
+		    lr->lr_outrefcnt, lr->lr_parentcnt );
+	    ber_err_print( msg );
+	    if ( lr->lr_binddn != NULL ) {
+		    sprintf( msg, "   pending bind DN: <%s>\n", lr->lr_binddn );
+		    ber_err_print( msg );
+	    }
+	}
+	LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
+
+	ber_err_print( "** Response Queue:\n" );
+	LDAP_MUTEX_LOCK( ld, LDAP_RESP_LOCK );
+	if (( lm = ld->ld_responses ) == NULLMSG ) {
+		ber_err_print( "   Empty\n" );
+	}
+	for ( ; lm != NULLMSG; lm = lm->lm_next ) {
+                sprintf( msg, " * 0x%p - msgid %d,  type %d\n",
+                    lm, lm->lm_msgid, lm->lm_msgtype );
+		ber_err_print( msg );
+		if (( l = lm->lm_chain ) != NULL ) {
+			ber_err_print( "   chained responses:\n" );
+			for ( ; l != NULLMSG; l = l->lm_chain ) {
+				sprintf( msg,
+                                    "  * 0x%p - msgid %d,  type %d\n",
+                                    l, l->lm_msgid, l->lm_msgtype );
+				ber_err_print( msg );
+			}
+		}
+	}
+	LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
+}
+#endif /* LDAP_DEBUG */
+
+
+LDAPRequest *
+nsldapi_new_request( LDAPConn *lc, BerElement *ber, int msgid, int expect_resp )
+{
+	LDAPRequest	*lr;
+
+	lr = (LDAPRequest *)NSLDAPI_CALLOC( 1, sizeof( LDAPRequest ));
+
+	if ( lr != NULL ) {
+		lr->lr_conn = lc;
+		lr->lr_ber = ber;
+		lr->lr_msgid = lr->lr_origid = msgid;
+		lr->lr_expect_resp = expect_resp;
+		lr->lr_status = LDAP_REQST_INPROGRESS;
+		lr->lr_res_errno = LDAP_SUCCESS;	/* optimistic */
+
+		if ( lc != NULL ) {	/* mark connection as in use */
+			++lc->lconn_refcnt;
+			lc->lconn_lastused = time( 0 );
+		}
+	}
+
+	return( lr );
+}
+
+
+void
+nsldapi_free_request( LDAP *ld, LDAPRequest *lr, int free_conn )
+{
+	LDAPRequest	*tmplr, *nextlr;
+
+	LDAPDebug( LDAP_DEBUG_TRACE,
+		"nsldapi_free_request 0x%p (origid %d, msgid %d)\n",
+		lr, lr->lr_origid, lr->lr_msgid );
+
+	if ( lr->lr_parent != NULL ) {
+		/* unlink child from parent */
+		lr->lr_parent->lr_child = NULL;
+		--lr->lr_parent->lr_outrefcnt;
+	}
+
+	if ( lr->lr_status == LDAP_REQST_WRITING ) {
+		--lr->lr_conn->lconn_pending_requests;
+	}
+
+	/* free all of our spawned referrals (child requests) */
+	for ( tmplr = lr->lr_child; tmplr != NULL; tmplr = nextlr ) {
+		nextlr = tmplr->lr_sibling;
+		nsldapi_free_request( ld, tmplr, free_conn );
+	}
+
+	if ( free_conn ) {
+		nsldapi_free_connection( ld, lr->lr_conn, NULL, NULL, 0, 1 );
+	}
+
+	if ( lr->lr_prev == NULL ) {
+		ld->ld_requests = lr->lr_next;
+	} else {
+		lr->lr_prev->lr_next = lr->lr_next;
+	}
+
+	if ( lr->lr_next != NULL ) {
+		lr->lr_next->lr_prev = lr->lr_prev;
+	}
+
+	if ( lr->lr_ber != NULL ) {
+		ber_free( lr->lr_ber, 1 );
+	}
+
+	if ( lr->lr_res_error != NULL ) {
+		NSLDAPI_FREE( lr->lr_res_error );
+	}
+
+	if ( lr->lr_res_matched != NULL ) {
+		NSLDAPI_FREE( lr->lr_res_matched );
+	}
+
+	if ( lr->lr_binddn != NULL ) {
+		NSLDAPI_FREE( lr->lr_binddn );
+	}
+
+	if ( lr->lr_res_ctrls != NULL ) {
+		ldap_controls_free( lr->lr_res_ctrls );
+	}
+	NSLDAPI_FREE( lr );
+}
+
+
+/*
+ * Add a request to the end of the list of outstanding requests.
+ * This function must be called with these two locks in hand, acquired in
+ * this order:
+ *	LDAP_CONN_LOCK
+ *	LDAP_REQ_LOCK
+ */
+void
+nsldapi_queue_request_nolock( LDAP *ld, LDAPRequest *lr )
+{
+        if ( NULL == ld->ld_requests ) {
+		ld->ld_requests = lr;
+        } else {
+                LDAPRequest     *tmplr;
+
+                for ( tmplr = ld->ld_requests; tmplr->lr_next != NULL;
+                                tmplr = tmplr->lr_next ) {
+                        ;
+                }
+                tmplr->lr_next = lr;
+                lr->lr_prev = tmplr;
+        }
+}
+
+
+static void
+free_servers( LDAPServer *srvlist )
+{
+    LDAPServer	*nextsrv;
+
+    while ( srvlist != NULL ) {
+	nextsrv = srvlist->lsrv_next;
+	if ( srvlist->lsrv_dn != NULL ) {
+		NSLDAPI_FREE( srvlist->lsrv_dn );
+	}
+	if ( srvlist->lsrv_host != NULL ) {
+		NSLDAPI_FREE( srvlist->lsrv_host );
+	}
+	NSLDAPI_FREE( srvlist );
+	srvlist = nextsrv;
+    }
+}
+
+
+/*
+ * Initiate chasing of LDAPv2+ (Umich extension) referrals.
+ *
+ * Returns an LDAP error code.
+ *
+ * Note that *hadrefp will be set to 1 if one or more referrals were found in
+ * "*errstrp" (even if we can't chase them) and zero if none were found.
+ * 
+ * XXX merging of errors in this routine needs to be improved.
+ */
+int
+nsldapi_chase_v2_referrals( LDAP *ld, LDAPRequest *lr, char **errstrp,
+    int *totalcountp, int *chasingcountp )
+{
+	char		*p, *ref, *unfollowed;
+	LDAPRequest	*origreq;
+	int		rc, tmprc, len, unknown;
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_chase_v2_referrals\n", 0, 0, 0 );
+
+	*totalcountp = *chasingcountp = 0;
+
+	if ( *errstrp == NULL ) {
+		return( LDAP_SUCCESS );
+	}
+
+	len = strlen( *errstrp );
+	for ( p = *errstrp; len >= LDAP_REF_STR_LEN; ++p, --len ) {
+		if (( *p == 'R' || *p == 'r' ) && strncasecmp( p,
+		    LDAP_REF_STR, LDAP_REF_STR_LEN ) == 0 ) {
+			*p = '\0';
+			p += LDAP_REF_STR_LEN;
+			break;
+		}
+	}
+
+	if ( len < LDAP_REF_STR_LEN ) {
+		return( LDAP_SUCCESS );
+	}
+
+	if ( lr->lr_parentcnt >= ld->ld_refhoplimit ) {
+		LDAPDebug( LDAP_DEBUG_TRACE,
+		    "more than %d referral hops (dropping)\n",
+		    ld->ld_refhoplimit, 0, 0 );
+		return( LDAP_REFERRAL_LIMIT_EXCEEDED );
+	}
+
+	/* find original request */
+	for ( origreq = lr; origreq->lr_parent != NULL;
+	     origreq = origreq->lr_parent ) {
+		;
+	}
+
+	unfollowed = NULL;
+	rc = LDAP_SUCCESS;
+
+	/* parse out & follow referrals */
+	for ( ref = p; rc == LDAP_SUCCESS && ref != NULL; ref = p ) {
+		if (( p = strchr( ref, '\n' )) != NULL ) {
+			*p++ = '\0';
+		} else {
+			p = NULL;
+		}
+
+		++*totalcountp;
+
+		rc = chase_one_referral( ld, lr, origreq, ref, "v2 referral",
+		    &unknown, 0 /* not a reference */ );
+
+		if ( rc != LDAP_SUCCESS || unknown ) {
+			if (( tmprc = nsldapi_append_referral( ld, &unfollowed,
+			    ref )) != LDAP_SUCCESS ) {
+				rc = tmprc;
+			}
+		} else {
+			++*chasingcountp;
+		}
+	}
+
+	NSLDAPI_FREE( *errstrp );
+	*errstrp = unfollowed;
+
+	return( rc );
+}
+
+
+/* returns an LDAP error code */
+int
+nsldapi_chase_v3_refs( LDAP *ld, LDAPRequest *lr, char **v3refs,
+    int is_reference, int *totalcountp, int *chasingcountp )
+{
+   	int		rc = LDAP_SUCCESS;
+	int		i, unknown;
+	LDAPRequest	*origreq;
+
+	*totalcountp = *chasingcountp = 0;
+
+	if ( v3refs == NULL || v3refs[0] == NULL ) {
+		return( LDAP_SUCCESS );
+	}
+
+	*totalcountp = 1;
+
+	if ( lr->lr_parentcnt >= ld->ld_refhoplimit ) {
+		LDAPDebug( LDAP_DEBUG_TRACE,
+		    "more than %d referral hops (dropping)\n",
+		    ld->ld_refhoplimit, 0, 0 );
+		return( LDAP_REFERRAL_LIMIT_EXCEEDED );
+	}
+
+	/* find original request */
+	for ( origreq = lr; origreq->lr_parent != NULL;
+	    origreq = origreq->lr_parent ) {
+		;
+	}
+
+	/*
+	 * in LDAPv3, we just need to follow one referral in the set.
+	 * we dp this by stopping as soon as we succeed in initiating a
+	 * chase on any referral (basically this means we were able to connect
+	 * to the server and bind).
+	 */
+	for ( i = 0; v3refs[i] != NULL; ++i ) {
+		rc = chase_one_referral( ld, lr, origreq, v3refs[i],
+		    is_reference ? "v3 reference" : "v3 referral", &unknown,
+		    is_reference );
+		if ( rc == LDAP_SUCCESS && !unknown ) {
+			*chasingcountp = 1;
+			break;
+		}
+	}
+
+	/* XXXmcs: should we save unfollowed referrals somewhere? */
+
+	return( rc );	/* last error is as good as any other I guess... */
+}
+
+
+/*
+ * returns an LDAP error code
+ *
+ * XXXmcs: this function used to have #ifdef LDAP_DNS code in it but I
+ *	removed it when I improved the parsing (we don't define LDAP_DNS
+ *	here at Netscape).
+ */
+static int
+chase_one_referral( LDAP *ld, LDAPRequest *lr, LDAPRequest *origreq,
+    char *refurl, char *desc, int *unknownp, int is_reference )
+{
+	int		rc, tmprc, secure, msgid;
+	LDAPServer	*srv;
+	BerElement	*ber;
+	LDAPURLDesc	*ludp;
+
+	*unknownp = 0;
+	ludp = NULLLDAPURLDESC;
+
+	if ( nsldapi_url_parse( refurl, &ludp, 0 ) != 0 ) {
+		LDAPDebug( LDAP_DEBUG_TRACE,
+		    "ignoring unknown %s <%s>\n", desc, refurl, 0 );
+		*unknownp = 1;
+		rc = LDAP_SUCCESS;
+		goto cleanup_and_return;
+	}
+
+	secure = (( ludp->lud_options & LDAP_URL_OPT_SECURE ) != 0 );
+
+/* XXXmcs: can't tell if secure is supported by connect callback */
+	if ( secure && ld->ld_extconnect_fn == NULL ) {
+		LDAPDebug( LDAP_DEBUG_TRACE,
+		    "ignoring LDAPS %s <%s>\n", desc, refurl, 0 );
+		*unknownp = 1;
+		rc = LDAP_SUCCESS;
+		goto cleanup_and_return;
+	}
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "chasing LDAP%s %s: <%s>\n",
+	    secure ? "S" : "", desc, refurl );
+
+	LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK );
+	msgid = ++ld->ld_msgid;
+	LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK );
+
+	if (( tmprc = re_encode_request( ld, origreq->lr_ber, msgid,
+	    ludp, &ber, is_reference )) != LDAP_SUCCESS ) {
+		rc = tmprc;
+		goto cleanup_and_return;
+	}
+
+	if (( srv = (LDAPServer *)NSLDAPI_CALLOC( 1, sizeof( LDAPServer )))
+	    == NULL ) {
+		ber_free( ber, 1 );
+		rc = LDAP_NO_MEMORY;
+		goto cleanup_and_return;
+	}
+
+	if ( ludp->lud_host == NULL && ld->ld_defhost == NULL ) {
+		srv->lsrv_host = NULL;
+	} else {
+		if ( ludp->lud_host == NULL ) {
+		  srv->lsrv_host =
+		    nsldapi_strdup( origreq->lr_conn->lconn_server->lsrv_host );
+		  LDAPDebug( LDAP_DEBUG_TRACE,
+		    "chase_one_referral: using hostname '%s' from original "
+		    "request on new request\n",
+		    srv->lsrv_host, 0, 0);
+		} else {
+		  srv->lsrv_host = nsldapi_strdup( ludp->lud_host );
+		  LDAPDebug( LDAP_DEBUG_TRACE,
+		    "chase_one_referral: using hostname '%s' as specified "
+		    "on new request\n",
+		    srv->lsrv_host, 0, 0);
+		}
+
+		if ( srv->lsrv_host == NULL ) {
+			NSLDAPI_FREE( (char *)srv );
+			ber_free( ber, 1 );
+			rc = LDAP_NO_MEMORY;
+			goto cleanup_and_return;
+		}
+	}
+
+	if ( ludp->lud_port == 0 && ludp->lud_host == NULL ) {
+		srv->lsrv_port = origreq->lr_conn->lconn_server->lsrv_port;
+		LDAPDebug( LDAP_DEBUG_TRACE,
+		    "chase_one_referral: using port (%d) from original "
+		    "request on new request\n",
+		    srv->lsrv_port, 0, 0);
+	} else if ( ludp->lud_port != 0 ) {
+		srv->lsrv_port = ludp->lud_port;
+		LDAPDebug( LDAP_DEBUG_TRACE,
+		    "chase_one_referral: using port (%d) as specified on "
+		    "new request\n",
+		    srv->lsrv_port, 0, 0);
+	} else {
+		srv->lsrv_port = secure ? LDAPS_PORT : LDAP_PORT;
+		LDAPDebug( LDAP_DEBUG_TRACE,
+		    "chase_one_referral: using default port (%d)\n",
+			srv->lsrv_port, 0, 0 );
+	}
+
+	if ( secure ) {
+		srv->lsrv_options |= LDAP_SRV_OPT_SECURE;
+	}
+
+	if ( nsldapi_send_server_request( ld, ber, msgid,
+	    lr, srv, NULL, NULL, 1 ) < 0 ) {
+		rc = LDAP_GET_LDERRNO( ld, NULL, NULL );
+		LDAPDebug( LDAP_DEBUG_ANY, "Unable to chase %s %s (%s)\n",
+		    desc, refurl, ldap_err2string( rc ));
+	} else {
+		rc = LDAP_SUCCESS;
+	}
+
+cleanup_and_return:
+	if ( ludp != NULLLDAPURLDESC ) {
+		ldap_free_urldesc( ludp );
+	}
+
+	return( rc );
+}
+
+
+/* returns an LDAP error code */
+int
+nsldapi_append_referral( LDAP *ld, char **referralsp, char *s )
+{
+	int	first;
+
+	if ( *referralsp == NULL ) {
+		first = 1;
+		*referralsp = (char *)NSLDAPI_MALLOC( strlen( s ) +
+		    LDAP_REF_STR_LEN + 1 );
+	} else {
+		first = 0;
+		*referralsp = (char *)NSLDAPI_REALLOC( *referralsp,
+		    strlen( *referralsp ) + strlen( s ) + 2 );
+	}
+
+	if ( *referralsp == NULL ) {
+		return( LDAP_NO_MEMORY );
+	}
+
+	if ( first ) {
+		strcpy( *referralsp, LDAP_REF_STR );
+	} else {
+		strcat( *referralsp, "\n" );
+	}
+	strcat( *referralsp, s );
+
+	return( LDAP_SUCCESS );
+}
+
+
+
+/* returns an LDAP error code */
+static int
+re_encode_request( LDAP *ld, BerElement *origber, int msgid, LDAPURLDesc *ludp,
+    BerElement **berp, int is_reference )
+{
+/*
+ * XXX this routine knows way too much about how the lber library works!
+ */
+	ber_int_t origmsgid;
+	ber_tag_t tag;
+	ber_int_t ver;
+	int			rc;
+	BerElement		*ber;
+	struct berelement	tmpber;
+	char			*dn, *orig_dn;
+	/* extra stuff for search request */
+	ber_int_t scope = -1;
+
+	LDAPDebug( LDAP_DEBUG_TRACE,
+	    "re_encode_request: new msgid %d, new dn <%s>\n",
+	    msgid, ( ludp->lud_dn == NULL ) ? "NONE" : ludp->lud_dn, 0 );
+
+	tmpber = *origber;
+
+	/*
+	 * All LDAP requests are sequences that start with a message id.  For
+	 * everything except delete requests, this is followed by a sequence
+	 * that is tagged with the operation code.  For deletes, there is just
+	 * a DN that is tagged with the operation code.
+	 */
+
+	/* skip past msgid and get operation tag */
+	if ( ber_scanf( &tmpber, "{it", &origmsgid, &tag ) == LBER_ERROR ) {
+		return( LDAP_DECODING_ERROR );
+	}
+
+	/*
+	 * XXXmcs: we don't support filters in search referrals yet,
+	 * so if present we return an error which is probably
+	 * better than just ignoring the extra info.
+	 * XXXrichm: we now support scopes.  Supporting filters would require
+	 * a lot more additional work to be able to read the filter from
+	 * the ber original search request, convert to string, etc.  It might
+	 * be better and easier to change nsldapi_build_search_req to have
+	 * some special mode by which you could tell it to skip filter and
+	 * attrlist encoding if no filter was given - then we could just
+	 * create a new ber search request with our new filter if present.
+	 */
+	if ( ( tag == LDAP_REQ_SEARCH ) && ( ludp->lud_filter != NULL )) {
+		return( LDAP_LOCAL_ERROR );
+	}
+
+	if ( tag == LDAP_REQ_BIND ) {
+		/* bind requests have a version number before the DN */
+		rc = ber_scanf( &tmpber, "{ia", &ver, &orig_dn );
+	} else if ( tag == LDAP_REQ_DELETE ) {
+		/* delete requests DNs are not within a sequence */
+		rc = ber_scanf( &tmpber, "a", &orig_dn );
+	} else if ( tag == LDAP_REQ_SEARCH ) {
+	    /* need scope */
+	    rc = ber_scanf( &tmpber, "{ae", &orig_dn, &scope );
+	} else {
+	    rc = ber_scanf( &tmpber, "{a", &orig_dn );
+	}
+
+	if ( rc == LBER_ERROR ) {
+	    return( LDAP_DECODING_ERROR );
+	}
+
+	if ( ludp->lud_dn == NULL ) {
+	    dn = orig_dn;
+	} else {
+	    dn = ludp->lud_dn;
+	    NSLDAPI_FREE( orig_dn );
+	    orig_dn = NULL;
+	}
+
+	if ( ludp->lud_scope != -1 ) {
+	    scope = ludp->lud_scope; /* scope provided by ref - use it */
+	} else if (is_reference) {
+	    /* 
+	     * RFC 4511 says that the we should use scope BASE in the
+	     * search reference if the client's original request was for scope
+	     * ONELEVEL - since the server did not include the scope in the 
+	     * search reference returned, we must provide the correct behavior
+	     * in the client (i.e. the correct behavior is implied)
+	     * see RFC 4511 section 4.5.3 for more information
+	     */
+	    if (scope == LDAP_SCOPE_ONELEVEL) {
+		scope = LDAP_SCOPE_BASE;
+	    }
+	}
+
+	/* allocate and build the new request */
+	if (( rc = nsldapi_alloc_ber_with_options( ld, &ber ))
+	    != LDAP_SUCCESS ) {
+		if ( orig_dn != NULL ) {
+			NSLDAPI_FREE( orig_dn );
+		}
+		return( rc );
+	}
+
+	if ( tag == LDAP_REQ_BIND ) {
+		rc = ber_printf( ber, "{it{is", msgid, tag, ver , dn );
+	} else if ( tag == LDAP_REQ_DELETE ) {
+	    rc = ber_printf( ber, "{its}", msgid, tag, dn );
+	} else if ( tag == LDAP_REQ_SEARCH ) {
+	    rc = ber_printf( ber, "{it{se", msgid, tag, dn, scope );
+	} else {
+	    rc = ber_printf( ber, "{it{s", msgid, tag, dn );
+	}
+
+	if ( orig_dn != NULL ) {
+		NSLDAPI_FREE( orig_dn );
+	}
+/*
+ * can't use "dn" or "orig_dn" from this point on (they've been freed)
+ */
+
+	if ( rc == -1 ) {
+		ber_free( ber, 1 );
+		return( LDAP_ENCODING_ERROR );
+	}
+
+	if ( tag != LDAP_REQ_DELETE &&
+	    ( ber_write( ber, tmpber.ber_ptr, ( tmpber.ber_end -
+	    tmpber.ber_ptr ), 0 ) != ( tmpber.ber_end - tmpber.ber_ptr )
+	    || ber_printf( ber, "}}" ) == -1 )) {
+		ber_free( ber, 1 );
+		return( LDAP_ENCODING_ERROR );
+	}
+
+#ifdef LDAP_DEBUG
+	if ( ldap_debug & LDAP_DEBUG_PACKETS ) {
+		LDAPDebug( LDAP_DEBUG_ANY, "re_encode_request new request is:\n",
+		    0, 0, 0 );
+		ber_dump( ber, 0 );
+	}
+#endif /* LDAP_DEBUG */
+
+	*berp = ber;
+	return( LDAP_SUCCESS );
+}
+
+
+LDAPRequest *
+nsldapi_find_request_by_msgid( LDAP *ld, int msgid )
+{
+    	LDAPRequest	*lr;
+
+	for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) {
+		if ( msgid == lr->lr_msgid ) {
+			break;
+		}
+	}
+
+	return( lr );
+}
+
+
+/*
+ * nsldapi_connection_lost_nolock() resets "ld" to a non-connected, known
+ * state.  It should be called whenever a fatal error occurs on the
+ * Sockbuf "sb."  sb == NULL means we don't know specifically where
+ * the problem was so we assume all connections are bad.
+ */
+void
+nsldapi_connection_lost_nolock( LDAP *ld, Sockbuf *sb )
+{
+	LDAPRequest	*lr;
+
+	/*
+	 * change status of all pending requests that are associated with "sb
+	 *	to "connection dead."
+	 * also change the connection status to "dead" and remove it from
+	 *	the list of sockets we are interested in.
+	 */
+	for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) {
+		if ( sb == NULL ||
+		    ( lr->lr_conn != NULL && lr->lr_conn->lconn_sb == sb )) {
+			lr->lr_status = LDAP_REQST_CONNDEAD;
+			if ( lr->lr_conn != NULL ) {
+				lr->lr_conn->lconn_status = LDAP_CONNST_DEAD;
+				nsldapi_iostatus_interest_clear( ld,
+				    lr->lr_conn->lconn_sb );
+			}
+		}
+	}
+}
+
+
+#ifdef LDAP_DNS
+static LDAPServer *
+dn2servers( LDAP *ld, char *dn )	/* dn can also be a domain.... */
+{
+	char		*p, *domain, *host, *server_dn, **dxs;
+	int		i, port;
+	LDAPServer	*srvlist, *prevsrv, *srv;
+
+	if (( domain = strrchr( dn, '@' )) != NULL ) {
+		++domain;
+	} else {
+		domain = dn;
+	}
+
+	if (( dxs = nsldapi_getdxbyname( domain )) == NULL ) {
+		LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+		return( NULL );
+	}
+
+	srvlist = NULL;
+
+	for ( i = 0; dxs[ i ] != NULL; ++i ) {
+		port = LDAP_PORT;
+		server_dn = NULL;
+		if ( strchr( dxs[ i ], ':' ) == NULL ) {
+			host = dxs[ i ];
+		} else if ( strlen( dxs[ i ] ) >= 7 &&
+		    strncmp( dxs[ i ], "ldap://", 7 ) == 0 ) {
+			host = dxs[ i ] + 7;
+			if (( p = strchr( host, ':' )) == NULL ) {
+				p = host;
+			} else {
+				*p++ = '\0';
+				port = atoi( p );
+			}
+			if (( p = strchr( p, '/' )) != NULL ) {
+				server_dn = ++p;
+				if ( *server_dn == '\0' ) {
+					server_dn = NULL;
+				}
+			}
+		} else {
+			host = NULL;
+		}
+
+		if ( host != NULL ) {	/* found a server we can use */
+			if (( srv = (LDAPServer *)NSLDAPI_CALLOC( 1,
+			    sizeof( LDAPServer ))) == NULL ) {
+				free_servers( srvlist );
+				srvlist = NULL;
+				break;		/* exit loop & return */
+			}
+
+			/* add to end of list of servers */
+			if ( srvlist == NULL ) {
+				srvlist = srv;
+			} else {
+				prevsrv->lsrv_next = srv;
+			}
+			prevsrv = srv;
+			
+			/* copy in info. */
+			if (( srv->lsrv_host = nsldapi_strdup( host )) == NULL
+			    || ( server_dn != NULL && ( srv->lsrv_dn =
+			    nsldapi_strdup( server_dn )) == NULL )) {
+				free_servers( srvlist );
+				srvlist = NULL;
+				break;		/* exit loop & return */
+			}
+			srv->lsrv_port = port;
+		}
+	}
+
+	ldap_value_free( dxs );
+
+	if ( srvlist == NULL ) {
+		LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN, NULL, NULL );
+	}
+
+	return( srvlist );
+}
+#endif /* LDAP_DNS */
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/reslist.c
@@ -0,0 +1,86 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ *  Copyright (c) 1990 Regents of the University of Michigan.
+ *  All rights reserved.
+ */
+/*
+ *  reslist.c
+ */
+
+#if 0
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+LDAPMessage *
+LDAP_CALL
+ldap_delete_result_entry( LDAPMessage **list, LDAPMessage *e )
+{
+	LDAPMessage	*tmp, *prev = NULL;
+    
+    if ( list == NULL || e == NULL ) {
+        return( NULL );
+    }
+
+	for ( tmp = *list; tmp != NULL && tmp != e; tmp = tmp->lm_chain )
+		prev = tmp;
+
+	if ( tmp == NULL )
+		return( NULL );
+
+	if ( prev == NULL )
+		*list = tmp->lm_chain;
+	else
+		prev->lm_chain = tmp->lm_chain;
+	tmp->lm_chain = NULL;
+
+	return( tmp );
+}
+
+void
+LDAP_CALL
+ldap_add_result_entry( LDAPMessage **list, LDAPMessage *e )
+{
+    if ( list != NULL && e != NULL ) {
+        e->lm_chain = *list;
+        *list = e;
+    }
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/result.c
@@ -0,0 +1,1473 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ *  Copyright (c) 1990 Regents of the University of Michigan.
+ *  All rights reserved.
+ */
+/*
+ *  result.c - wait for an ldap result
+ */
+
+#if 0
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+/*
+ * Special return values used by some functions (wait4msg() and read1msg()).
+ */
+#define NSLDAPI_RESULT_TIMEOUT          0
+#define NSLDAPI_RESULT_ERROR            (-1)
+#define NSLDAPI_RESULT_NOT_FOUND        (-2)
+
+static int check_response_queue( LDAP *ld, int msgid, int all,
+	int do_abandon_check, LDAPMessage **result );
+static int ldap_abandoned( LDAP *ld, int msgid );
+static int ldap_mark_abandoned( LDAP *ld, int msgid );
+static int wait4msg( LDAP *ld, int msgid, int all, int unlock_permitted,
+	struct timeval *timeout, LDAPMessage **result );
+static int read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb, LDAPConn **lcp,
+	LDAPMessage **result );
+static void check_for_refs( LDAP *ld, LDAPRequest *lr, BerElement *ber,
+	int ldapversion, int *totalcountp, int *chasingcountp );
+static int build_result_ber( LDAP *ld, BerElement **berp, LDAPRequest *lr );
+static void merge_error_info( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr );
+#if defined( CLDAP )
+static int cldap_select1( LDAP *ld, struct timeval *timeout );
+#endif
+static void link_pend( LDAP *ld, LDAPPend *lp );
+
+/*
+ * ldap_result - wait for an ldap result response to a message from the
+ * ldap server.  If msgid is -1, any message will be accepted, otherwise
+ * ldap_result will wait for a response with msgid.  If all is 0 the
+ * first message with id msgid will be accepted, otherwise, ldap_result
+ * will wait for all responses with id msgid and then return a pointer to
+ * the entire list of messages.  This is only useful for search responses,
+ * which can be of two message types (zero or more entries, followed by an
+ * ldap result).  The type of the first message received is returned.
+ * When waiting, any messages that have been abandoned are discarded.
+ *
+ * Example:
+ *	ldap_result( s, msgid, all, timeout, result )
+ */
+int
+LDAP_CALL
+ldap_result(
+    LDAP 		*ld,
+    int 		msgid,
+    int 		all,
+    struct timeval	*timeout,
+    LDAPMessage		**result
+)
+{
+	int		rc;
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_result\n", 0, 0, 0 );
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( -1 );	/* punt */
+	}
+
+	LDAP_MUTEX_LOCK( ld, LDAP_RESULT_LOCK );
+
+	rc = nsldapi_result_nolock(ld, msgid, all, 1, timeout, result);
+
+	LDAP_MUTEX_UNLOCK( ld, LDAP_RESULT_LOCK );
+
+	return( rc );
+}
+
+
+int
+nsldapi_result_nolock( LDAP *ld, int msgid, int all, int unlock_permitted,
+    struct timeval *timeout, LDAPMessage **result )
+{
+	int		rc;
+
+	LDAPDebug( LDAP_DEBUG_TRACE,
+		"nsldapi_result_nolock (msgid=%d, all=%d)\n", msgid, all, 0 );
+
+	/*
+	 * First, look through the list of responses we have received on
+	 * this association and see if the response we're interested in
+	 * is there.  If it is, return it.  If not, call wait4msg() to
+	 * wait until it arrives or timeout occurs.
+	 */
+
+	if ( result == NULL ) {
+		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+		return( -1 );
+	}
+
+	if ( check_response_queue( ld, msgid, all, 1, result ) != 0 ) {
+		LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL );
+		rc = (*result)->lm_msgtype;
+	} else {
+		rc = wait4msg( ld, msgid, all, unlock_permitted, timeout,
+		    result );
+	}
+
+	/*
+	 * XXXmcs should use cache function pointers to hook in memcache
+	 */
+	if ( ld->ld_memcache != NULL && NSLDAPI_SEARCH_RELATED_RESULT( rc ) &&
+	     !((*result)->lm_fromcache )) {
+		ldap_memcache_append( ld, (*result)->lm_msgid,
+		    (all || NSLDAPI_IS_SEARCH_RESULT( rc )), *result );
+	}
+
+	return( rc );
+}
+
+
+/*
+ * Look through the list of queued responses for a message that matches the
+ * criteria in the msgid and all parameters.  msgid == LDAP_RES_ANY matches
+ * all ids.
+ *
+ * If an appropriate message is found, a non-zero value is returned and the
+ * message is dequeued and assigned to *result.
+ *
+ * If not, *result is set to NULL and this function returns 0.
+ */
+static int
+check_response_queue( LDAP *ld, int msgid, int all, int do_abandon_check,
+    LDAPMessage **result )
+{
+	LDAPMessage	*lm, *lastlm, *nextlm;
+	LDAPRequest	*lr;
+
+	LDAPDebug( LDAP_DEBUG_TRACE,
+	    "=> check_response_queue (msgid=%d, all=%d)\n", msgid, all, 0 );
+
+	*result = NULL;
+	lastlm = NULL;
+	LDAP_MUTEX_LOCK( ld, LDAP_RESP_LOCK );
+	for ( lm = ld->ld_responses; lm != NULL; lm = nextlm ) {
+		nextlm = lm->lm_next;
+
+		if ( do_abandon_check && ldap_abandoned( ld, lm->lm_msgid ) ) {
+			ldap_mark_abandoned( ld, lm->lm_msgid );
+
+			if ( lastlm == NULL ) {
+				ld->ld_responses = lm->lm_next;
+			} else {
+				lastlm->lm_next = nextlm;
+			}
+
+			ldap_msgfree( lm );
+
+			continue;
+		}
+
+		if ( msgid == LDAP_RES_ANY || lm->lm_msgid == msgid ) {
+			LDAPMessage	*tmp;
+
+			if ( all == 0
+			    || (lm->lm_msgtype != LDAP_RES_SEARCH_RESULT
+			    && lm->lm_msgtype != LDAP_RES_SEARCH_REFERENCE
+			    && lm->lm_msgtype != LDAP_RES_SEARCH_ENTRY) )
+				break;
+
+			for ( tmp = lm; tmp != NULL; tmp = tmp->lm_chain ) {
+				if ( tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT )
+					break;
+			}
+
+			if ( tmp == NULL ) {
+				LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
+				LDAPDebug( LDAP_DEBUG_TRACE,
+				    "<= check_response_queue NOT FOUND\n",
+				    0, 0, 0 );
+				return( 0 );	/* no message to return */
+			}
+
+			break;
+		}
+		lastlm = lm;
+	}
+
+	/*
+	 * if we did not find a message OR if the one we found is a result for
+	 * a request that is still pending, return failure.
+	 */
+	if ( lm == NULL 
+             || (( lr = nsldapi_find_request_by_msgid( ld, lm->lm_msgid ))
+		   != NULL && lr->lr_outrefcnt > 0 )) {
+		LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
+		LDAPDebug( LDAP_DEBUG_TRACE,
+		    "<= check_response_queue NOT FOUND\n",
+		    0, 0, 0 );
+		return( 0 );	/* no message to return */
+	}
+
+	if ( all == 0 ) {
+		if ( lm->lm_chain == NULL ) {
+			if ( lastlm == NULL ) {
+				ld->ld_responses = lm->lm_next;
+			} else {
+				lastlm->lm_next = lm->lm_next;
+			}
+		} else {
+			if ( lastlm == NULL ) {
+				ld->ld_responses = lm->lm_chain;
+				ld->ld_responses->lm_next = lm->lm_next;
+			} else {
+				lastlm->lm_next = lm->lm_chain;
+				lastlm->lm_next->lm_next = lm->lm_next;
+			}
+		}
+	} else {
+		if ( lastlm == NULL ) {
+			ld->ld_responses = lm->lm_next;
+		} else {
+			lastlm->lm_next = lm->lm_next;
+		}
+	}
+
+	if ( all == 0 ) {
+		lm->lm_chain = NULL;
+	}
+	lm->lm_next = NULL;
+	LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
+
+	*result = lm;
+	LDAPDebug( LDAP_DEBUG_TRACE,
+	    "<= check_response_queue returning msgid %d type %d\n",
+	    lm->lm_msgid, lm->lm_msgtype, 0 );
+	return( 1 );	/* a message was found and returned in *result */
+}
+
+
+/*
+ * wait4msg(): Poll for incoming LDAP messages, respecting the timeout.
+ *
+ * Return values:
+ *  > 0:                      message received; value is the tag of the message.
+ *  NSLDAPI_RESULT_TIMEOUT    timeout exceeded.
+ *  NSLDAPI_RESULT_ERROR      fatal error occurred such as connection closed.
+ */
+static int
+wait4msg( LDAP *ld, int msgid, int all, int unlock_permitted,
+	struct timeval *timeout, LDAPMessage **result )
+{
+	int		err, rc = NSLDAPI_RESULT_NOT_FOUND, msgfound;
+	struct timeval	tv, *tvp;
+	long		start_time = 0, tmp_time;
+	LDAPConn	*lc, *nextlc;
+	/* lr points to the specific request we are waiting for, if any */
+	LDAPRequest	*lr = NULL;
+
+#ifdef LDAP_DEBUG
+	if ( timeout == NULL ) {
+		LDAPDebug( LDAP_DEBUG_TRACE, "wait4msg (infinite timeout)\n",
+		    0, 0, 0 );
+	} else {
+		LDAPDebug( LDAP_DEBUG_TRACE, "wait4msg (timeout %ld sec, %ld usec)\n",
+		    timeout->tv_sec, (long) timeout->tv_usec, 0 );
+	}
+#endif /* LDAP_DEBUG */
+
+	/* check the cache */
+	if ( ld->ld_cache_on && ld->ld_cache_result != NULL ) {
+		/* if ( unlock_permitted ) LDAP_MUTEX_UNLOCK( ld ); */
+		LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK );
+		rc = (ld->ld_cache_result)( ld, msgid, all, timeout, result );
+		LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+		/* if ( unlock_permitted ) LDAP_MUTEX_LOCK( ld ); */
+		if ( rc != NSLDAPI_RESULT_TIMEOUT ) {
+			return( rc );
+		}
+		if ( ld->ld_cache_strategy == LDAP_CACHE_LOCALDB ) {
+			LDAP_SET_LDERRNO( ld, LDAP_TIMEOUT, NULL, NULL );
+			return( NSLDAPI_RESULT_TIMEOUT );
+		}
+	}
+
+	/*
+	 * if we are looking for a specific msgid, check to see if it is
+	 * associated with a dead connection and return an error if so.
+	 */
+	if ( msgid != LDAP_RES_ANY && msgid != LDAP_RES_UNSOLICITED ) {
+		LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
+		if (( lr = nsldapi_find_request_by_msgid( ld, msgid ))
+		    == NULL ) {
+			LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
+			LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL,
+				nsldapi_strdup( "unknown message id" ));
+			return( NSLDAPI_RESULT_ERROR );	/* could not find request for msgid */
+		}
+		if ( lr->lr_conn != NULL &&
+		    lr->lr_conn->lconn_status == LDAP_CONNST_DEAD ) {
+			nsldapi_free_request( ld, lr, 1 );
+			LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
+			LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN, NULL, NULL );
+			return( NSLDAPI_RESULT_ERROR );	/* connection dead */
+		}
+		LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
+	}
+
+	if ( timeout == NULL ) {
+		tvp = NULL;
+	} else {
+		tv = *timeout;
+		tvp = &tv;
+		start_time = (long)time( NULL );
+	}
+
+	rc = NSLDAPI_RESULT_NOT_FOUND;
+	while ( rc == NSLDAPI_RESULT_NOT_FOUND ) {
+		msgfound = 0;
+#ifdef LDAP_DEBUG
+		if ( ldap_debug & LDAP_DEBUG_TRACE ) {
+			nsldapi_dump_connection( ld, ld->ld_conns, 1 );
+			nsldapi_dump_requests_and_responses( ld );
+		}
+#endif /* LDAP_DEBUG */
+
+		/*
+		 * Check if we have some data in a connection's BER buffer.
+		 * If so, use it.
+		 */
+		LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK );
+		LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
+		for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
+			if ( lc->lconn_sb->sb_ber.ber_ptr <
+			    lc->lconn_sb->sb_ber.ber_end ) {
+				/* read1msg() might free the connection. */
+				rc = read1msg( ld, msgid, all, lc->lconn_sb,
+				    &lc, result );
+				/* Indicate to next segment that we've processed a message
+				   (or several, via chased refs) this time around. */
+				msgfound = 1;
+				break;
+			}
+		}
+		LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
+		LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
+
+		if ( !msgfound ) {
+			/*
+			 * There was no buffered data. Poll to check connection
+			 * status (read/write readiness).
+			 */
+			err = nsldapi_iostatus_poll( ld, tvp );
+
+#if defined( LDAP_DEBUG ) && !defined( macintosh ) && !defined( DOS )
+			if ( err == -1 ) {
+			    LDAPDebug( LDAP_DEBUG_TRACE,
+				    "nsldapi_iostatus_poll returned -1: errno %d\n",
+				    LDAP_GET_ERRNO( ld ), 0, 0 );
+			}
+#endif
+
+#if !defined( macintosh ) && !defined( DOS )
+			/*
+			 * If the restart option is enabled and the error
+			 * was EINTR, try again.
+			 */
+			if ( err == -1
+			    && 0 != ( ld->ld_options & LDAP_BITOPT_RESTART )
+			    && LDAP_GET_ERRNO( ld ) == EINTR ) {
+				continue;
+			}
+#endif
+
+			/*
+			 * Handle timeouts (no activity) and fatal errors.
+			 */
+			if ( err == -1 || err == 0 ) {
+				LDAP_SET_LDERRNO( ld, (err == -1 ?
+				    LDAP_SERVER_DOWN : LDAP_TIMEOUT), NULL,
+				    NULL );
+				if ( err == -1 ) {
+					LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
+					nsldapi_connection_lost_nolock( ld,
+						NULL );
+					LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
+					rc = NSLDAPI_RESULT_ERROR;
+				} else {
+					rc = NSLDAPI_RESULT_TIMEOUT;
+				}
+				return( rc );
+			}
+
+			/*
+			 * Check each connection for interesting activity.
+			 */
+			LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK );
+			LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
+			for ( lc = ld->ld_conns;
+			    rc == NSLDAPI_RESULT_NOT_FOUND && lc != NULL;
+			    lc = nextlc ) {
+				nextlc = lc->lconn_next;
+
+				/*
+				 * For connections that are in the CONNECTING
+				 * state, check for write ready (which
+				 * indicates that the connection completed) and
+				 * transition to the CONNECTED state.
+				 */
+				if ( lc->lconn_status == LDAP_CONNST_CONNECTING
+				    && nsldapi_iostatus_is_write_ready( ld,
+				    lc->lconn_sb ) ) {
+					lc->lconn_status = LDAP_CONNST_CONNECTED;
+					LDAPDebug( LDAP_DEBUG_TRACE,
+					"wait4msg: connection 0x%p -"
+					" LDAP_CONNST_CONNECTING ->"
+					" LDAP_CONNST_CONNECTED\n",
+					lc, 0, 0 );
+				}
+
+				if ( lc->lconn_status
+				    != LDAP_CONNST_CONNECTED ) {
+					continue;
+				}
+
+				/*
+				* For connections that are CONNECTED, check
+				* for read ready (which indicates that data
+				* from server is available), and, for
+				* connections with associated requests that
+				* have not yet been sent, write ready (okay
+				* to send some data to the server).
+				*/
+				if ( nsldapi_iostatus_is_read_ready( ld,
+				    lc->lconn_sb )) {
+				/* read1msg() might free the connection. */
+					rc = read1msg( ld, msgid, all,
+					    lc->lconn_sb, &lc, result );
+				}
+
+				/*
+				 * Send pending requests if possible.  If there is no lc then
+				 * it was a child connection closed by read1msg().
+				 */
+				if ( lc && lc->lconn_pending_requests > 0
+				    && nsldapi_iostatus_is_write_ready( ld,
+				    lc->lconn_sb )) {
+					err = nsldapi_send_pending_requests_nolock(
+					    ld, lc );
+					if ( err == -1 &&
+					    rc == NSLDAPI_RESULT_NOT_FOUND ) {
+						rc = NSLDAPI_RESULT_ERROR;
+					}
+				}
+
+			}
+
+			LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
+			LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
+		}
+
+		/*
+		 * It is possible that recursion occurred while chasing
+		 * referrals and as a result the message we are looking
+		 * for may have been placed on the response queue.  Look
+		 * for it there before continuing so we don't end up
+		 * waiting on the network for a message that we already
+		 * received!
+		 */
+		if ( rc == NSLDAPI_RESULT_NOT_FOUND &&
+		    check_response_queue( ld, msgid, all, 0, result ) != 0 ) {
+			LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL );
+			rc = (*result)->lm_msgtype;
+		}
+
+		/*
+		 * honor the timeout if specified
+		 */
+		if ( rc == NSLDAPI_RESULT_NOT_FOUND && tvp != NULL ) {
+			tmp_time = (long)time( NULL );
+			if (( tv.tv_sec -=  ( tmp_time - start_time )) <= 0 ) {
+				rc = NSLDAPI_RESULT_TIMEOUT;
+				LDAP_SET_LDERRNO( ld, LDAP_TIMEOUT, NULL,
+				    NULL );
+				break;
+			}
+
+			LDAPDebug( LDAP_DEBUG_TRACE, "wait4msg:  %ld secs to go\n",
+				tv.tv_sec, 0, 0 );
+			start_time = tmp_time;
+		}
+	}
+
+	return( rc );
+}
+
+
+#define NSLDAPI_REQUEST_COMPLETE( lr )				\
+	( (lr)->lr_outrefcnt <= 0 && 				\
+	  (lr)->lr_res_msgtype != LDAP_RES_SEARCH_ENTRY &&	\
+	  (lr)->lr_res_msgtype != LDAP_RES_SEARCH_REFERENCE )
+
+/*
+ * read1msg() should be called with LDAP_CONN_LOCK and LDAP_REQ_LOCK locked.
+ *
+ * Return values:
+ *  > 0:                      message received; value is the tag of the message.
+ *  NSLDAPI_RESULT_TIMEOUT    timeout exceeded.
+ *  NSLDAPI_RESULT_ERROR      fatal error occurred such as connection closed.
+ *  NSLDAPI_RESULT_NOT_FOUND  message not yet complete; keep waiting.
+ *
+ *  The LDAPConn passed in my be freed by read1msg() if the reference count
+ *  shows that it's no longer needed.
+ */
+static int
+read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb, LDAPConn **lcp,
+    LDAPMessage **result )
+{
+	BerElement	*ber;
+	LDAPMessage	*new, *l, *prev, *chainprev, *tmp;
+	ber_int_t	id;
+	ber_tag_t	tag;
+	ber_len_t	len;
+	int		terrno, lderr, foundit = 0;
+	LDAPRequest	*lr;
+	int		rc, has_parent, message_can_be_returned;
+	int		manufactured_result = 0;
+	LDAPConn	*lc = *lcp;
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "read1msg\n", 0, 0, 0 );
+
+	message_can_be_returned = 1;	/* the usual case... */
+
+	/*
+	 * if we are not already in the midst of reading a message, allocate
+	 * a ber that is associated with this connection
+	 */
+	if ( lc->lconn_ber == NULLBER && nsldapi_alloc_ber_with_options( ld,
+	    &lc->lconn_ber ) != LDAP_SUCCESS ) {
+		return( NSLDAPI_RESULT_ERROR );
+	}
+
+	/*
+	 * ber_get_next() doesn't set errno on EOF, so we pre-set it to
+	 * zero to avoid getting tricked by leftover "EAGAIN" errors
+	 */
+	LDAP_SET_ERRNO( ld, 0 );
+
+	/* get the next message */
+	if ( (tag = ber_get_next( sb, &len, lc->lconn_ber ))
+	    != LDAP_TAG_MESSAGE ) {
+		terrno = LDAP_GET_ERRNO( ld );
+		if ( terrno == EWOULDBLOCK || terrno == EAGAIN ) {
+		    return( NSLDAPI_RESULT_NOT_FOUND );	/* try again */
+		}
+		LDAP_SET_LDERRNO( ld, (tag == LBER_DEFAULT ? LDAP_SERVER_DOWN :
+                    LDAP_LOCAL_ERROR), NULL, NULL );
+		if ( tag == LBER_DEFAULT ) {
+			nsldapi_connection_lost_nolock( ld, sb );
+		}
+		return( NSLDAPI_RESULT_ERROR );
+	}
+
+	/*
+	 * Since we have received a complete message now, we pull this ber
+	 * out of the connection structure and never read into it again.
+	 */
+	ber = lc->lconn_ber;
+	lc->lconn_ber = NULLBER;
+
+	/* message id */
+	if ( ber_get_int( ber, &id ) == LBER_ERROR ) {
+		ber_free( ber, 1 );
+		LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
+		return( NSLDAPI_RESULT_ERROR );
+	}
+
+	/* if it's been abandoned, toss it */
+	if ( ldap_abandoned( ld, (int)id ) ) {
+		ber_free( ber, 1 );
+		return( NSLDAPI_RESULT_NOT_FOUND );	/* continue looking */
+	}
+
+	if ( id == LDAP_RES_UNSOLICITED ) {
+		lr = NULL;
+	} else if (( lr = nsldapi_find_request_by_msgid( ld, id )) == NULL ) {
+		LDAPDebug( LDAP_DEBUG_ANY,
+		    "no request for response with msgid %d (tossing)\n",
+		    id, 0, 0 );
+		ber_free( ber, 1 );
+		return( NSLDAPI_RESULT_NOT_FOUND );	/* continue looking */
+	}
+
+	/* the message type */
+	if ( (tag = ber_peek_tag( ber, &len )) == LBER_ERROR ) {
+		ber_free( ber, 1 );
+		LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
+		return( NSLDAPI_RESULT_ERROR );
+	}
+	LDAPDebug( LDAP_DEBUG_TRACE, "got %s msgid %d, original id %d\n",
+	    ( tag == LDAP_RES_SEARCH_ENTRY ) ? "ENTRY" :
+	    ( tag == LDAP_RES_SEARCH_REFERENCE ) ? "REFERENCE" : "RESULT", id,
+	    ( lr == NULL ) ? id : lr->lr_origid );
+
+	if ( lr != NULL ) {
+		id = lr->lr_origid;
+		lr->lr_res_msgtype = tag;
+	}
+	rc = NSLDAPI_RESULT_NOT_FOUND;	/* default is to keep looking (no response found) */
+
+	if ( id != LDAP_RES_UNSOLICITED && ( tag == LDAP_RES_SEARCH_REFERENCE ||
+	    tag != LDAP_RES_SEARCH_ENTRY )) {
+		int		refchasing, reftotal, simple_request = 0;
+		LDAPControl **ctrls = NULL;
+
+		check_for_refs( ld, lr, ber, lc->lconn_version, &reftotal,
+		    &refchasing );
+
+		if ( refchasing > 0 || lr->lr_outrefcnt > 0 ) {
+			/*
+			 * we're chasing one or more new refs...
+			 */
+			ber_free( ber, 1 );
+			ber = NULLBER;
+			lr->lr_status = LDAP_REQST_CHASINGREFS;
+			message_can_be_returned = 0;
+
+		} else if ( tag != LDAP_RES_SEARCH_REFERENCE ) {
+			/*
+			 * this request is complete...
+			 */
+			has_parent = ( lr->lr_parent != NULL );
+
+			if ( lr->lr_outrefcnt <= 0 && !has_parent ) {
+				/* request without any refs */
+				simple_request = ( reftotal == 0 );
+			}
+
+			/*
+			 * If this is not a child request and it is a bind
+			 * request, reset the connection's bind DN and
+			 * status based on the result of the operation.
+			 */
+			if ( !has_parent &&
+			    LDAP_RES_BIND == lr->lr_res_msgtype &&
+			    lr->lr_conn != NULL ) {
+				if ( lr->lr_conn->lconn_binddn != NULL ) {
+					NSLDAPI_FREE(
+					    lr->lr_conn->lconn_binddn );
+				}
+				if ( LDAP_SUCCESS == nsldapi_parse_result( ld,
+				    lr->lr_res_msgtype, ber, &lderr, NULL,
+				    NULL, NULL, NULL )
+				    && LDAP_SUCCESS == lderr ) {
+					lr->lr_conn->lconn_bound = 1;
+					lr->lr_conn->lconn_binddn =
+					    lr->lr_binddn;
+					lr->lr_binddn = NULL;
+				} else {
+					lr->lr_conn->lconn_bound = 0;
+					lr->lr_conn->lconn_binddn = NULL;
+				}
+			}
+
+			/*
+			 * if this response is to a child request, we toss
+			 * the message contents and just merge error info.
+			 * into the parent.
+			 */
+			if ( has_parent ) {
+				/* Extract any response controls from ber before ditching it */
+				if( nsldapi_find_controls( ber, &ctrls ) != LDAP_SUCCESS ) {
+					ber_free( ber, 1 );
+					LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
+					return( NSLDAPI_RESULT_ERROR );
+				}
+
+				ber_free( ber, 1 );
+				ber = NULLBER;
+			}
+			while ( lr->lr_parent != NULL ) {
+				merge_error_info( ld, lr->lr_parent, lr );
+
+				lr = lr->lr_parent;
+				--lr->lr_outrefcnt;
+				if ( !NSLDAPI_REQUEST_COMPLETE(lr)) {
+					break;
+				}
+			}
+			/* Stash response controls in original request so they can be baked
+			   into the manufactured result message later */
+			if( ctrls != NULL ) {
+				if( lr->lr_res_ctrls != NULL ) {
+					/* There are controls saved in original request already,
+					   replace them with the new ones because we only save
+					   the final controls received.
+					   May want to arrange for merging intermediate response
+					   controls into the array in the future */
+					ldap_controls_free( lr->lr_res_ctrls );
+				}
+				lr->lr_res_ctrls = ctrls;
+			}
+
+			/*
+			 * we recognize a request as fully complete when:
+			 *  1) it is not a child request (NULL parent)
+			 *  2) it has no outstanding referrals
+			 *  3) we have received a result for the request (i.e.,
+			 *     something other than an entry or a reference).
+			 */
+			if ( lr->lr_parent == NULL
+			    && NSLDAPI_REQUEST_COMPLETE(lr)) {
+				id = lr->lr_msgid;
+				tag = lr->lr_res_msgtype;
+				LDAPDebug( LDAP_DEBUG_TRACE,
+				    "request %d done\n", id, 0, 0 );
+LDAPDebug( LDAP_DEBUG_TRACE,
+"res_errno: %d, res_error: <%s>, res_matched: <%s>\n",
+lr->lr_res_errno, lr->lr_res_error ? lr->lr_res_error : "",
+lr->lr_res_matched ? lr->lr_res_matched : "" );
+				if ( !simple_request ) {
+					if ( ber != NULLBER ) {
+						ber_free( ber, 1 );
+						ber = NULLBER;
+					}
+					if ( build_result_ber( ld, &ber, lr )
+					    != LDAP_SUCCESS ) {
+                                                rc = NSLDAPI_RESULT_ERROR;
+					} else {
+						manufactured_result = 1;
+					}
+				}
+
+				nsldapi_free_request( ld, lr, 1 );
+				/* Since we asked nsldapi_free_request() to free the
+				   connection, lets make sure our callers know it's gone. */
+				*lcp = NULL;
+			} else {
+				message_can_be_returned = 0;
+			}
+		}
+	}
+
+	if ( ber == NULLBER ) {
+		return( rc );
+	}
+
+	/* make a new ldap message */
+	if ( (new = (LDAPMessage*)NSLDAPI_CALLOC( 1, sizeof(struct ldapmsg) ))
+	    == NULL ) {
+		LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+                return( NSLDAPI_RESULT_ERROR );
+	}
+	new->lm_msgid = (int)id;
+	new->lm_msgtype = tag;
+	new->lm_ber = ber;
+
+	/*
+	 * if this is a search entry or if this request is complete (i.e.,
+	 * there are no outstanding referrals) then add to cache and check
+	 * to see if we should return this to the caller right away or not.
+	 */
+	if ( message_can_be_returned ) {
+		if ( ld->ld_cache_on ) {
+			nsldapi_add_result_to_cache( ld, new );
+		}
+
+		if ( msgid == LDAP_RES_ANY || id == msgid ) {
+			if ( new->lm_msgtype == LDAP_RES_SEARCH_RESULT ) {
+				/*
+				 * return the first response we have for this
+				 * search request later (possibly an entire
+				 * chain of messages).
+				 */
+				foundit = 1;
+			} else if ( all == 0
+			    || (new->lm_msgtype != LDAP_RES_SEARCH_REFERENCE
+			    && new->lm_msgtype != LDAP_RES_SEARCH_ENTRY) ) {
+				*result = new;
+				LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL,
+				    NULL );
+				return( tag );
+			}
+		}
+	}
+
+	/* 
+	 * if not, we must add it to the list of responses.  if
+	 * the msgid is already there, it must be part of an existing
+	 * search response.
+	 */
+
+	prev = NULL;
+	LDAP_MUTEX_LOCK( ld, LDAP_RESP_LOCK );
+	for ( l = ld->ld_responses; l != NULL; l = l->lm_next ) {
+		if ( l->lm_msgid == new->lm_msgid )
+			break;
+		prev = l;
+	}
+
+	/* not part of an existing search response */
+	if ( l == NULL ) {
+		if ( foundit ) {
+			LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
+			*result = new;
+			LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL );
+			return( tag );
+		}
+
+		new->lm_next = ld->ld_responses;
+		ld->ld_responses = new;
+		LDAPDebug( LDAP_DEBUG_TRACE,
+		    "adding new response id %d type %d (looking for id %d)\n",
+		    new->lm_msgid, new->lm_msgtype, msgid );
+		LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
+		if( message_can_be_returned )
+			POST( ld, new->lm_msgid, new );
+                return( NSLDAPI_RESULT_NOT_FOUND );  /* continue looking */
+	}
+
+	LDAPDebug( LDAP_DEBUG_TRACE,
+            "adding response 0x%p - id %d type %d",
+            new, new->lm_msgid, new->lm_msgtype );
+        LDAPDebug( LDAP_DEBUG_TRACE, " (looking for id %d)\n", msgid, 0, 0 );
+
+	/*
+	 * part of a search response - add to end of list of entries
+	 *
+	 * the first step is to find the end of the list of entries and
+	 * references.  after the following loop is executed, tmp points to
+	 * the last entry or reference in the chain.  If there are none,
+	 * tmp points to the search result.
+	 */
+	chainprev = NULL;
+	for ( tmp = l; tmp->lm_chain != NULL &&
+	    ( tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_ENTRY
+	    || tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_REFERENCE );
+	    tmp = tmp->lm_chain ) {
+		chainprev = tmp;
+	}
+
+	/*
+	 * If this is a manufactured result message and a result is already
+	 * queued we throw away the one that is queued and replace it with
+	 * our new result.  This is necessary so we don't end up returning
+	 * more than one result.
+	 */
+	if ( manufactured_result &&
+	    tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT ) {
+		/*
+		 * the result is the only thing in the chain... replace it.
+		 */
+		new->lm_chain = tmp->lm_chain;
+		new->lm_next = tmp->lm_next;
+		if ( chainprev == NULL ) {
+			if ( prev == NULL ) {
+				ld->ld_responses = new;
+			} else {
+				prev->lm_next = new;
+			}
+		} else {
+		    chainprev->lm_chain = new;
+		}
+		if ( l == tmp ) {
+			l = new;
+		}
+		ldap_msgfree( tmp );
+
+	} else if ( manufactured_result && tmp->lm_chain != NULL
+	    && tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_RESULT ) {
+		/*
+		 * entries or references are also present, so the result
+		 * is the next entry after tmp.  replace it.
+		 */
+		new->lm_chain = tmp->lm_chain->lm_chain;
+		new->lm_next = tmp->lm_chain->lm_next;
+		ldap_msgfree( tmp->lm_chain );
+		tmp->lm_chain = new;
+
+	} else if ( tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT ) {
+		/*
+		 * the result is the only thing in the chain... add before it.
+		 */
+		new->lm_chain = tmp;
+		if ( chainprev == NULL ) {
+			if ( prev == NULL ) {
+				ld->ld_responses = new;
+			} else {
+				prev->lm_next = new;
+			}
+		} else {
+		    chainprev->lm_chain = new;
+		}
+		if ( l == tmp ) {
+			l = new;
+		}
+
+	} else {
+		/*
+		 * entries and/or references are present... add to the end
+		 * of the entry/reference part of the chain.
+		 */
+		new->lm_chain = tmp->lm_chain;
+		tmp->lm_chain = new;
+	}
+
+	/*
+	 * return the first response or the whole chain if that's what
+	 * we were looking for....
+	 */
+	if ( foundit ) {
+		if ( all == 0 && l->lm_chain != NULL ) {
+			/*
+			 * only return the first response in the chain
+			 */
+			if ( prev == NULL ) {
+				ld->ld_responses = l->lm_chain;
+			} else {
+				prev->lm_next = l->lm_chain;
+			}
+			l->lm_chain = NULL;
+			tag = l->lm_msgtype;
+		} else {
+			/*
+			 * return all of the responses (may be a chain)
+			 */
+			if ( prev == NULL ) {
+				ld->ld_responses = l->lm_next;
+			} else {
+				prev->lm_next = l->lm_next;
+			}
+		}
+		*result = l;
+		LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
+		LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL );
+		return( tag );
+	}
+	LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
+        return( NSLDAPI_RESULT_NOT_FOUND );     /* continue looking */
+}
+
+
+/*
+ * check for LDAPv2+ (UMich extension) or LDAPv3 referrals or references
+ * errors are merged in "lr".
+ */
+static void
+check_for_refs( LDAP *ld, LDAPRequest *lr, BerElement *ber,
+    int ldapversion, int *totalcountp, int *chasingcountp )
+{
+	int		err, origerr;
+	char		*errstr, *matcheddn, **v3refs;
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "check_for_refs\n", 0, 0, 0 );
+
+	*chasingcountp = *totalcountp = 0;
+
+	if ( ldapversion < LDAP_VERSION2 || ( lr->lr_parent == NULL
+	    && ( ld->ld_options & LDAP_BITOPT_REFERRALS ) == 0 )) {
+		/* referrals are not supported or are disabled */
+		return;
+	}
+
+	if ( lr->lr_res_msgtype == LDAP_RES_SEARCH_REFERENCE ) {
+		err = nsldapi_parse_reference( ld, ber, &v3refs, NULL );
+		origerr = LDAP_REFERRAL;	/* a small lie... */
+		matcheddn = errstr = NULL;
+	} else {
+		err = nsldapi_parse_result( ld, lr->lr_res_msgtype, ber,
+		    &origerr, &matcheddn, &errstr, &v3refs, NULL );
+	}
+
+	if ( err != LDAP_SUCCESS ) {
+		/* parse failed */
+		return;
+	}
+
+	if ( origerr == LDAP_REFERRAL ) {	/* ldapv3 */
+		if ( v3refs != NULL ) {
+			err = nsldapi_chase_v3_refs( ld, lr, v3refs,
+			    ( lr->lr_res_msgtype == LDAP_RES_SEARCH_REFERENCE ),
+			    totalcountp, chasingcountp );
+			ldap_value_free( v3refs );
+		}
+	} else if ( ldapversion == LDAP_VERSION2
+	    && origerr != LDAP_SUCCESS ) {
+		/* referrals may be present in the error string */
+		err = nsldapi_chase_v2_referrals( ld, lr, &errstr,
+		    totalcountp, chasingcountp );
+	}
+
+	/* set LDAP errno, message, and matched string appropriately */
+	if ( lr->lr_res_error != NULL ) {
+		NSLDAPI_FREE( lr->lr_res_error );
+	}
+	lr->lr_res_error = errstr;
+
+	if ( lr->lr_res_matched != NULL ) {
+		NSLDAPI_FREE( lr->lr_res_matched );
+	}
+	lr->lr_res_matched = matcheddn;
+
+	if ( err == LDAP_SUCCESS && ( *chasingcountp == *totalcountp )) {
+		if ( *totalcountp > 0 && ( origerr == LDAP_PARTIAL_RESULTS
+		    || origerr == LDAP_REFERRAL )) {
+			/* substitute success for referral error codes */
+			lr->lr_res_errno = LDAP_SUCCESS;
+		} else {
+			/* preserve existing non-referral error code */
+			lr->lr_res_errno = origerr;
+		}
+	} else if ( err != LDAP_SUCCESS ) {
+		/* error occurred while trying to chase referrals */
+		lr->lr_res_errno = err;
+	} else {
+		/* some referrals were not recognized */
+		lr->lr_res_errno = ( ldapversion == LDAP_VERSION2 )
+		    ? LDAP_PARTIAL_RESULTS : LDAP_REFERRAL;
+	}
+		
+	LDAPDebug( LDAP_DEBUG_TRACE,
+	    "check_for_refs: new result: msgid %d, res_errno %d, ",
+	    lr->lr_msgid, lr->lr_res_errno, 0 );
+	LDAPDebug( LDAP_DEBUG_TRACE, " res_error <%s>, res_matched <%s>\n",
+	    lr->lr_res_error ? lr->lr_res_error : "",
+	    lr->lr_res_matched ? lr->lr_res_matched : "", 0 );
+	LDAPDebug( LDAP_DEBUG_TRACE,
+	    "check_for_refs: %d new refs(s); chasing %d of them\n",
+	    *totalcountp, *chasingcountp, 0 );
+}
+
+
+/* returns an LDAP error code and also sets it in LDAP * */
+static int
+build_result_ber( LDAP *ld, BerElement **berp, LDAPRequest *lr )
+{
+	ber_len_t	len;
+	ber_int_t	along;
+	BerElement	*ber;
+	int		err;
+
+	if (( err = nsldapi_alloc_ber_with_options( ld, &ber ))
+	    != LDAP_SUCCESS ) {
+		return( err );
+	}
+	*berp = ber;
+	if ( ber_printf( ber, lr->lr_res_ctrls ? "{it{ess}" : "{it{ess}}",
+	    lr->lr_msgid, (long)lr->lr_res_msgtype, lr->lr_res_errno,
+	    lr->lr_res_matched ? lr->lr_res_matched : "",
+	    lr->lr_res_error ? lr->lr_res_error : "" ) == -1 ) {
+		return( LDAP_ENCODING_ERROR );
+	}
+
+	if ( NULL != lr->lr_res_ctrls && nsldapi_put_controls( ld,
+	    lr->lr_res_ctrls, 1 /* close seq */, ber ) != LDAP_SUCCESS ) {
+		return( LDAP_ENCODING_ERROR );
+	}
+
+	ber_reset( ber, 1 );
+	if ( ber_skip_tag( ber, &len ) == LBER_ERROR ||
+	    ber_get_int( ber, &along ) == LBER_ERROR ||
+	    ber_peek_tag( ber, &len ) == LBER_ERROR ) {
+		return( LDAP_DECODING_ERROR );
+	}
+
+	return( LDAP_SUCCESS );
+}
+
+
+static void
+merge_error_info( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr )
+{
+/*
+ * Merge error information in "lr" with "parentr" error code and string.
+ */
+	if ( lr->lr_res_errno == LDAP_PARTIAL_RESULTS ) {
+		parentr->lr_res_errno = lr->lr_res_errno;
+		if ( lr->lr_res_error != NULL ) {
+			(void)nsldapi_append_referral( ld, &parentr->lr_res_error,
+			    lr->lr_res_error );
+		}
+	} else if ( lr->lr_res_errno != LDAP_SUCCESS &&
+	    parentr->lr_res_errno == LDAP_SUCCESS ) {
+		parentr->lr_res_errno = lr->lr_res_errno;
+		if ( parentr->lr_res_error != NULL ) {
+			NSLDAPI_FREE( parentr->lr_res_error );
+		}
+		parentr->lr_res_error = lr->lr_res_error;
+		lr->lr_res_error = NULL;
+		if ( NAME_ERROR( lr->lr_res_errno )) {
+			if ( parentr->lr_res_matched != NULL ) {
+				NSLDAPI_FREE( parentr->lr_res_matched );
+			}
+			parentr->lr_res_matched = lr->lr_res_matched;
+			lr->lr_res_matched = NULL;
+		}
+	}
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "merged parent (id %d) error info:  ",
+	    parentr->lr_msgid, 0, 0 );
+	LDAPDebug( LDAP_DEBUG_TRACE, "result lderrno %d, error <%s>, matched <%s>\n",
+	    parentr->lr_res_errno, parentr->lr_res_error ?
+	    parentr->lr_res_error : "", parentr->lr_res_matched ?
+	    parentr->lr_res_matched : "" );
+}
+
+#if defined( CLDAP )
+#if !defined( macintosh ) && !defined( DOS ) && !defined( _WINDOWS ) && !defined(XP_OS2)
+/* XXXmcs: was revised to support extended I/O callbacks but never compiled! */
+static int
+cldap_select1( LDAP *ld, struct timeval *timeout )
+{
+	int		rc;
+	static int	tblsize = 0;
+	NSLDAPIIOStatus	*iosp = ld->ld_iostatus;
+
+	if ( tblsize == 0 ) {
+#ifdef USE_SYSCONF
+		tblsize = sysconf( _SC_OPEN_MAX );
+#else /* USE_SYSCONF */
+		tblsize = getdtablesize();
+#endif /* USE_SYSCONF */
+	}
+
+	if ( tblsize >= FD_SETSIZE ) {
+		/*
+		 * clamp value so we don't overrun the fd_set structure
+		 */
+		tblsize = FD_SETSIZE - 1;
+	}
+
+	if ( NSLDAPI_IOSTATUS_TYPE_OSNATIVE == iosp->ios_type ) {
+		fd_set		readfds;
+
+		FD_ZERO( &readfds );
+		FD_SET( ld->ld_sbp->sb_sd, &readfds );
+
+		/* XXXmcs: UNIX platforms should use poll() */
+		rc = select( tblsize, &readfds, 0, 0, timeout ) );
+
+	} else if ( NSLDAPI_IOSTATUS_TYPE_CALLBACK == iosp->ios_type ) {
+		LDAP_X_PollFD	pollfds[ 1 ];
+
+		pollfds[0].lpoll_fd = ld->ld_sbp->sb_sd;
+		pollfds[0].lpoll_arg = ld->ld_sbp->sb_arg;
+		pollfds[0].lpoll_events = LDAP_X_POLLIN;
+		pollfds[0].lpoll_revents = 0;
+		rc = ld->ld_extpoll_fn( pollfds, 1, nsldapi_tv2ms( timeout ),
+		    ld->ld_ext_session_arg );
+	} else {
+		LDAPDebug( LDAP_DEBUG_ANY,
+		    "nsldapi_iostatus_poll: unknown I/O type %d\n",
+		rc = 0; /* simulate a timeout (what else to do?) */
+	}
+
+	return( rc );
+}
+#endif /* !macintosh */
+
+
+#ifdef macintosh
+static int
+cldap_select1( LDAP *ld, struct timeval *timeout )
+{
+	/* XXXmcs: needs to be revised to support I/O callbacks */
+	return( tcpselect( ld->ld_sbp->sb_sd, timeout ));
+}
+#endif /* macintosh */
+
+
+#if (defined( DOS ) && defined( WINSOCK )) || defined( _WINDOWS ) || defined(XP_OS2)
+/* XXXmcs: needs to be revised to support extended I/O callbacks */
+static int
+cldap_select1( LDAP *ld, struct timeval *timeout )
+{
+    fd_set          readfds;
+    int             rc;
+
+    FD_ZERO( &readfds );
+    FD_SET( ld->ld_sbp->sb_sd, &readfds );
+
+    if ( NSLDAPI_IO_TYPE_STANDARD == ld->ldiou_type &&
+	NULL != ld->ld_select_fn ) {
+	    rc = ld->ld_select_fn( 1, &readfds, 0, 0, timeout );
+    } else if ( NSLDAPI_IO_TYPE_EXTENDED == ld->ldiou_type &&
+	NULL != ld->ld_extselect_fn ) {
+	    rc = ld->ld_extselect_fn( ld->ld_ext_session_arg, 1, &readfds, 0,
+		0, timeout ) );
+    } else {
+	    /* XXXmcs: UNIX platforms should use poll() */
+	    rc = select( 1, &readfds, 0, 0, timeout ) );
+    }
+
+    return( rc == SOCKET_ERROR ? -1 : rc );
+}
+#endif /* WINSOCK || _WINDOWS */
+#endif /* CLDAP */
+
+int
+LDAP_CALL
+ldap_msgfree( LDAPMessage *lm )
+{
+	LDAPMessage	*next;
+	int		type = 0;
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_msgfree\n", 0, 0, 0 );
+
+	for ( ; lm != NULL; lm = next ) {
+		next = lm->lm_chain;
+		type = lm->lm_msgtype;
+		ber_free( lm->lm_ber, 1 );
+		NSLDAPI_FREE( (char *) lm );
+	}
+
+	return( type );
+}
+
+/*
+ * ldap_msgdelete - delete a message.  It returns:
+ *	0	if the entire message was deleted
+ *	-1	if the message was not found, or only part of it was found
+ */
+int
+ldap_msgdelete( LDAP *ld, int msgid )
+{
+	LDAPMessage	*lm, *prev;
+	int		msgtype;
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_msgdelete\n", 0, 0, 0 );
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( -1 );	/* punt */
+	}
+
+	prev = NULL;
+        LDAP_MUTEX_LOCK( ld, LDAP_RESP_LOCK );
+	for ( lm = ld->ld_responses; lm != NULL; lm = lm->lm_next ) {
+		if ( lm->lm_msgid == msgid )
+			break;
+		prev = lm;
+	}
+
+	if ( lm == NULL )
+	{
+        	LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
+		return( -1 );
+	}
+
+	if ( prev == NULL )
+		ld->ld_responses = lm->lm_next;
+	else
+		prev->lm_next = lm->lm_next;
+        LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
+
+	msgtype = ldap_msgfree( lm );
+	if ( msgtype == LDAP_RES_SEARCH_ENTRY
+	    || msgtype == LDAP_RES_SEARCH_REFERENCE ) {
+		return( -1 );
+	}
+
+	return( 0 );
+}
+
+
+/*
+ * return 1 if message msgid is waiting to be abandoned, 0 otherwise
+ */
+static int
+ldap_abandoned( LDAP *ld, int msgid )
+{
+	int	i;
+
+	LDAP_MUTEX_LOCK( ld, LDAP_ABANDON_LOCK );
+	if ( ld->ld_abandoned == NULL )
+	{
+		LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
+		return( 0 );
+	}
+
+	for ( i = 0; ld->ld_abandoned[i] != -1; i++ )
+		if ( ld->ld_abandoned[i] == msgid )
+		{
+			LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
+			return( 1 );
+		}
+
+	LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
+	return( 0 );
+}
+
+
+static int
+ldap_mark_abandoned( LDAP *ld, int msgid )
+{
+	int	i;
+
+	LDAP_MUTEX_LOCK( ld, LDAP_ABANDON_LOCK );
+	if ( ld->ld_abandoned == NULL )
+	{
+		LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
+		return( -1 );
+	}
+
+	for ( i = 0; ld->ld_abandoned[i] != -1; i++ )
+		if ( ld->ld_abandoned[i] == msgid )
+			break;
+
+	if ( ld->ld_abandoned[i] == -1 )
+	{
+		LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
+		return( -1 );
+	}
+
+	for ( ; ld->ld_abandoned[i] != -1; i++ ) {
+		ld->ld_abandoned[i] = ld->ld_abandoned[i + 1];
+	}
+
+	LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
+	return( 0 );
+}
+
+
+#ifdef CLDAP
+int
+cldap_getmsg( LDAP *ld, struct timeval *timeout, BerElement **ber )
+{
+	int		rc;
+	ber_tag_t	tag;
+	ber_len_t len;
+
+	if ( ld->ld_sbp->sb_ber.ber_ptr >= ld->ld_sbp->sb_ber.ber_end ) {
+		rc = cldap_select1( ld, timeout );
+		if ( rc == -1 || rc == 0 ) {
+			LDAP_SET_LDERRNO( ld, (rc == -1 ? LDAP_SERVER_DOWN :
+			    LDAP_TIMEOUT), NULL, NULL );
+			return( rc );
+		}
+	}
+
+	/* get the next message */
+	if ( (tag = ber_get_next( ld->ld_sbp, &len, ber ))
+	    != LDAP_TAG_MESSAGE ) {
+		LDAP_SET_LDERRNO( ld, (tag == LBER_DEFAULT ? LDAP_SERVER_DOWN :
+		    LDAP_LOCAL_ERROR), NULL, NULL );
+		return( -1 );
+	}
+
+	return( tag );
+}
+#endif /* CLDAP */
+
+int
+nsldapi_post_result( LDAP *ld, int msgid, LDAPMessage *result )
+{
+	LDAPPend	*lp;
+
+	LDAPDebug( LDAP_DEBUG_TRACE,
+	    "nsldapi_post_result(ld=0x%p, msgid=%d, result=0x%p)\n",
+	    ld, msgid, result );
+	LDAP_MUTEX_LOCK( ld, LDAP_PEND_LOCK );
+	if( msgid == LDAP_RES_ANY ) {
+		/*
+		 * Look for any pending request for which someone is waiting.
+		 */
+		for( lp = ld->ld_pend; lp != NULL; lp = lp->lp_next )
+		{
+			if ( lp->lp_sema != NULL ) {
+				break;
+			} 
+		}
+		/*
+		 * If we did't find a pending request, lp is NULL at this
+		 * point, and we will leave this function without doing
+		 * anything more -- which is exactly what we want to do.
+		 */
+	}
+	else
+	{
+		/*
+		 * Look for a pending request specific to this message id
+		 */
+		for( lp = ld->ld_pend; lp != NULL; lp = lp->lp_next )
+		{
+			if( lp->lp_msgid == msgid )
+				break;
+		}
+
+		if( lp == NULL )
+		{
+			/*
+			 * No pending requests for this response... append to
+			 * our pending result list.
+			 */
+			LDAPPend	*newlp;
+			newlp = (LDAPPend *)NSLDAPI_CALLOC( 1,
+			    sizeof( LDAPPend ));
+			if( newlp == NULL )
+			{
+				LDAP_MUTEX_UNLOCK( ld, LDAP_PEND_LOCK );
+				LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL,
+				    NULL );
+				return (-1);
+			}
+			newlp->lp_msgid = msgid;
+			newlp->lp_result = result;
+			link_pend( ld, newlp );
+		}
+	}
+
+
+	if( lp != NULL )
+	{
+		/*
+		 * Wake up a thread that is waiting for this result.
+		 */
+		lp->lp_msgid = msgid;
+		lp->lp_result = result;
+		LDAP_SEMA_POST( ld, lp );
+	}
+
+	LDAP_MUTEX_UNLOCK( ld, LDAP_PEND_LOCK );
+	return (0);
+}
+
+static void
+link_pend( LDAP *ld, LDAPPend *lp )
+{
+	if (( lp->lp_next = ld->ld_pend ) != NULL )
+	{
+		lp->lp_next->lp_prev = lp;    
+	} 
+	ld->ld_pend = lp; 
+	lp->lp_prev = NULL; 
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/saslbind.c
@@ -0,0 +1,877 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+#include "ldap-int.h"
+
+#ifdef LDAP_SASLIO_HOOKS
+/*
+ * Global SASL Init data
+ */
+
+static int
+nsldapi_sasl_fail()
+{
+        return( SASL_FAIL );
+}
+
+sasl_callback_t client_callbacks[] = {
+        { SASL_CB_GETOPT, nsldapi_sasl_fail, NULL },
+        { SASL_CB_GETREALM, NULL, NULL },
+        { SASL_CB_USER, NULL, NULL },
+        { SASL_CB_CANON_USER, NULL, NULL },
+        { SASL_CB_AUTHNAME, NULL, NULL },
+        { SASL_CB_PASS, NULL, NULL },
+        { SASL_CB_ECHOPROMPT, NULL, NULL },
+        { SASL_CB_NOECHOPROMPT, NULL, NULL },
+        { SASL_CB_LIST_END, NULL, NULL }
+};
+
+int
+nsldapi_sasl_cvterrno( LDAP *ld, int err, char *msg )
+{
+        int rc = LDAP_LOCAL_ERROR;
+
+        switch (err) {
+        case SASL_OK:
+                rc = LDAP_SUCCESS;
+                break;
+        case SASL_NOMECH:
+                rc = LDAP_AUTH_UNKNOWN;
+                break;
+        case SASL_BADSERV:
+                rc = LDAP_CONNECT_ERROR;
+                break;
+        case SASL_DISABLED:
+        case SASL_ENCRYPT:
+        case SASL_EXPIRED:
+        case SASL_NOUSERPASS:
+        case SASL_NOVERIFY:
+        case SASL_PWLOCK:
+        case SASL_TOOWEAK:
+        case SASL_UNAVAIL:
+        case SASL_WEAKPASS:
+                rc = LDAP_INAPPROPRIATE_AUTH;
+                break;
+        case SASL_BADAUTH:
+        case SASL_NOAUTHZ:
+                rc = LDAP_INVALID_CREDENTIALS;
+                break;
+        case SASL_NOMEM:
+                rc = LDAP_NO_MEMORY;
+                break;
+        case SASL_NOUSER:
+                rc = LDAP_NO_SUCH_OBJECT;
+                break;
+        case SASL_CONTINUE:
+        case SASL_FAIL:
+        case SASL_INTERACT:
+        default:
+                rc = LDAP_LOCAL_ERROR;
+                break;
+        }
+
+        LDAP_SET_LDERRNO( ld, rc, NULL, msg );
+        return( rc );
+}
+
+#ifdef LDAP_SASLIO_GET_MECHS_FROM_SERVER
+/*
+ * Get available SASL Mechanisms supported by the server
+ */
+
+static int
+nsldapi_get_sasl_mechs ( LDAP *ld, char **pmech )
+{
+        char *attr[] = { "supportedSASLMechanisms", NULL };
+        char **values, **v, *mech, *m;
+        LDAPMessage *res, *e;
+        struct timeval  timeout;
+        int slen, rc;
+
+        if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+                return( LDAP_PARAM_ERROR );
+        }
+
+        timeout.tv_sec = SEARCH_TIMEOUT_SECS;
+        timeout.tv_usec = 0;
+
+        rc = ldap_search_st( ld, "", LDAP_SCOPE_BASE,
+                "objectclass=*", attr, 0, &timeout, &res );
+
+        if ( rc != LDAP_SUCCESS ) {
+                return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+        }
+
+        e = ldap_first_entry( ld, res );
+        if ( e == NULL ) {
+                ldap_msgfree( res );
+                if ( ld->ld_errno == LDAP_SUCCESS ) {
+                        LDAP_SET_LDERRNO( ld, LDAP_NO_SUCH_OBJECT, NULL, NULL );
+                }
+                return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+        }
+
+        values = ldap_get_values( ld, e, "supportedSASLMechanisms" );
+        if ( values == NULL ) {
+                ldap_msgfree( res );
+                LDAP_SET_LDERRNO( ld, LDAP_NO_SUCH_ATTRIBUTE, NULL, NULL );
+                return( LDAP_NO_SUCH_ATTRIBUTE );
+        }
+
+        slen = 0;
+        for(v = values; *v != NULL; v++ ) {
+                slen += strlen(*v) + 1;
+        }
+        if ( (mech = NSLDAPI_CALLOC(1, slen)) == NULL) {
+                ldap_value_free( values );
+                ldap_msgfree( res );
+                LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+                return( LDAP_NO_MEMORY );
+        }
+        m = mech;
+        for(v = values; *v; v++) {
+                if (v != values) {
+                        *m++ = ' ';
+                }
+                slen = strlen(*v);
+                strncpy(m, *v, slen);
+                m += slen;
+        }
+        *m = '\0';
+
+        ldap_value_free( values );
+        ldap_msgfree( res );
+
+        *pmech = mech;
+
+        return( LDAP_SUCCESS );
+}
+#endif /* LDAP_SASLIO_GET_MECHS_FROM_SERVER */
+
+int
+nsldapi_sasl_secprops(
+        const char *in,
+        sasl_security_properties_t *secprops )
+{
+        int i;
+        char **props = NULL;
+        char *inp;
+        unsigned sflags = 0;
+        sasl_ssf_t max_ssf = 0;
+        sasl_ssf_t min_ssf = 0;
+        unsigned maxbufsize = 0;
+        int got_sflags = 0;
+        int got_max_ssf = 0;
+        int got_min_ssf = 0;
+        int got_maxbufsize = 0;
+
+        if (in == NULL) {
+                return LDAP_PARAM_ERROR;
+        }
+        inp = nsldapi_strdup(in);
+        if (inp == NULL) {
+                return LDAP_PARAM_ERROR;
+        }
+        props = ldap_str2charray( inp, "," );
+        NSLDAPI_FREE( inp );
+
+        if( props == NULL || secprops == NULL ) {
+                return LDAP_PARAM_ERROR;
+        }
+
+        for( i=0; props[i]; i++ ) {
+                if( strcasecmp(props[i], "none") == 0 ) {
+                        got_sflags++;
+
+                } else if( strcasecmp(props[i], "noactive") == 0 ) {
+                        got_sflags++;
+                        sflags |= SASL_SEC_NOACTIVE;
+
+                } else if( strcasecmp(props[i], "noanonymous") == 0 ) {
+                        got_sflags++;
+                        sflags |= SASL_SEC_NOANONYMOUS;
+
+                } else if( strcasecmp(props[i], "nodict") == 0 ) {
+                        got_sflags++;
+                        sflags |= SASL_SEC_NODICTIONARY;
+
+                } else if( strcasecmp(props[i], "noplain") == 0 ) {
+                        got_sflags++;
+                        sflags |= SASL_SEC_NOPLAINTEXT;
+
+                } else if( strcasecmp(props[i], "forwardsec") == 0 ) {
+                        got_sflags++;
+                        sflags |= SASL_SEC_FORWARD_SECRECY;
+
+                } else if( strcasecmp(props[i], "passcred") == 0 ) {
+                        got_sflags++;
+                        sflags |= SASL_SEC_PASS_CREDENTIALS;
+
+                } else if( strncasecmp(props[i],
+                        "minssf=", sizeof("minssf")) == 0 ) {
+                        if( isdigit( props[i][sizeof("minssf")] ) ) {
+                                got_min_ssf++;
+                                min_ssf = atoi( &props[i][sizeof("minssf")] );
+                        } else {
+                                return LDAP_NOT_SUPPORTED;
+                        }
+
+                } else if( strncasecmp(props[i],
+                        "maxssf=", sizeof("maxssf")) == 0 ) {
+                        if( isdigit( props[i][sizeof("maxssf")] ) ) {
+                                got_max_ssf++;
+                                max_ssf = atoi( &props[i][sizeof("maxssf")] );
+                        } else {
+                                return LDAP_NOT_SUPPORTED;
+                        }
+
+                } else if( strncasecmp(props[i],
+                        "maxbufsize=", sizeof("maxbufsize")) == 0 ) {
+                        if( isdigit( props[i][sizeof("maxbufsize")] ) ) {
+                                got_maxbufsize++;
+                                maxbufsize = atoi( &props[i][sizeof("maxbufsize")] );
+                                if( maxbufsize &&
+                                    (( maxbufsize < SASL_MIN_BUFF_SIZE )
+                                    || (maxbufsize > SASL_MAX_BUFF_SIZE ))) {
+                                        return( LDAP_PARAM_ERROR );
+                                }
+                        } else {
+                                return( LDAP_NOT_SUPPORTED );
+                        }
+                } else {
+                        return( LDAP_NOT_SUPPORTED );
+                }
+        }
+
+        if(got_sflags) {
+                secprops->security_flags = sflags;
+        }
+        if(got_min_ssf) {
+                secprops->min_ssf = min_ssf;
+        }
+        if(got_max_ssf) {
+                secprops->max_ssf = max_ssf;
+        }
+        if(got_maxbufsize) {
+                secprops->maxbufsize = maxbufsize;
+        }
+
+        ldap_charray_free( props );
+        return( LDAP_SUCCESS );
+}
+#endif /* LDAP_SASLIO_HOOKS */
+
+static int
+nsldapi_sasl_bind_s(
+    LDAP                *ld,
+    const char          *dn,
+    const char          *mechanism,
+    const struct berval *cred,
+    LDAPControl         **serverctrls,
+    LDAPControl         **clientctrls,
+    struct berval       **servercredp,
+    LDAPControl         ***responsectrls
+)
+{
+        int             err, msgid;
+        LDAPMessage     *result;
+
+        LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_sasl_bind_s\n", 0, 0, 0 );
+
+        if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+                return( LDAP_PARAM_ERROR );
+        }
+
+        if ( NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION3 ) {
+                LDAP_SET_LDERRNO( ld, LDAP_NOT_SUPPORTED, NULL, NULL );
+                return( LDAP_NOT_SUPPORTED );
+        }
+
+        if ( ( err = ldap_sasl_bind( ld, dn, mechanism, cred, serverctrls,
+            clientctrls, &msgid )) != LDAP_SUCCESS )
+                return( err );
+
+        if ( ldap_result( ld, msgid, 1, (struct timeval *) 0, &result ) == -1 )
+                return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+
+        /* Get the controls sent by the server if requested */
+        if ( responsectrls ) {
+                if ( ( err = ldap_parse_result( ld, result, &err, NULL, NULL,
+                       NULL, responsectrls, 0 )) != LDAP_SUCCESS )
+                    return( err );
+        }
+
+        err = ldap_parse_sasl_bind_result( ld, result, servercredp, 0 );
+        if (err != LDAP_SUCCESS  && err != LDAP_SASL_BIND_IN_PROGRESS) {
+                ldap_msgfree( result );
+                return( err );
+        }
+
+        return( ldap_result2error( ld, result, 1 ) );
+}
+
+#ifdef LDAP_SASLIO_HOOKS
+static int
+nsldapi_sasl_do_bind( LDAP *ld, const char *dn,
+        const char *mechs, unsigned flags,
+        LDAP_SASL_INTERACT_PROC *callback, void *defaults,
+        LDAPControl **sctrl, LDAPControl **cctrl, LDAPControl ***rctrl )
+{
+        sasl_interact_t *prompts = NULL;
+        sasl_conn_t     *ctx = NULL;
+        sasl_ssf_t      *ssf = NULL;
+        const char      *mech = NULL;
+        int             saslrc, rc;
+        struct berval   ccred;
+        unsigned        credlen;
+        int stepnum = 1;
+        char *sasl_username = NULL;
+
+        if (rctrl) {
+            /* init to NULL so we can call ldap_controls_free below */
+            *rctrl = NULL;
+        }
+
+        if (NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION3) {
+                LDAP_SET_LDERRNO( ld, LDAP_NOT_SUPPORTED, NULL, NULL );
+                return( LDAP_NOT_SUPPORTED );
+        }
+
+        /* shouldn't happen */
+        if (callback == NULL) {
+                return( LDAP_LOCAL_ERROR );
+        }
+
+        if ( (rc = nsldapi_sasl_open(ld, NULL, &ctx, 0)) != LDAP_SUCCESS ) {
+            return( rc );
+        }
+
+        ccred.bv_val = NULL;
+        ccred.bv_len = 0;
+
+        LDAPDebug(LDAP_DEBUG_TRACE, "Starting SASL/%s authentication\n",
+                  (mechs ? mechs : ""), 0, 0 );
+
+        do {
+                saslrc = sasl_client_start( ctx,
+                        mechs,
+                        &prompts,
+                        (const char **)&ccred.bv_val,
+                        &credlen,
+                        &mech );
+
+                LDAPDebug(LDAP_DEBUG_TRACE, "Doing step %d of client start for SASL/%s authentication\n",
+                          stepnum, (mech ? mech : ""), 0 );
+                stepnum++;
+
+                if( saslrc == SASL_INTERACT &&
+                    (callback)(ld, flags, defaults, prompts) != LDAP_SUCCESS ) {
+                        break;
+                }
+        } while ( saslrc == SASL_INTERACT );
+
+        ccred.bv_len = credlen;
+
+        if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
+                return( nsldapi_sasl_cvterrno( ld, saslrc, nsldapi_strdup( sasl_errdetail( ctx ) ) ) );
+        }
+
+        stepnum = 1;
+
+        do {
+                struct berval *scred;
+                int clientstepnum = 1;
+
+                scred = NULL;
+
+                if (rctrl) {
+                    /* if we're looping again, we need to free any controls set
+                       during the previous loop */
+                    /* NOTE that this assumes we only care about the controls
+                       returned by the last call to nsldapi_sasl_bind_s - if
+                       we care about _all_ controls, we will have to figure out
+                       some way to append them each loop go round */
+                    ldap_controls_free(*rctrl);
+                    *rctrl = NULL;
+                }
+
+                LDAPDebug(LDAP_DEBUG_TRACE, "Doing step %d of bind for SASL/%s authentication\n",
+                          stepnum, (mech ? mech : ""), 0 );
+                stepnum++;
+
+                /* notify server of a sasl bind step */
+                rc = nsldapi_sasl_bind_s(ld, dn, mech, &ccred,
+                                      sctrl, cctrl, &scred, rctrl); 
+
+                if ( ccred.bv_val != NULL ) {
+                        ccred.bv_val = NULL;
+                }
+
+                if ( rc != LDAP_SUCCESS && rc != LDAP_SASL_BIND_IN_PROGRESS ) {
+                        ber_bvfree( scred );
+                        return( rc );
+                }
+
+                if( rc == LDAP_SUCCESS && saslrc == SASL_OK ) {
+                        /* we're done, no need to step */
+                        if( scred ) {
+                            if ( scred->bv_len == 0 ) { /* MS AD sends back empty screds */
+                                LDAPDebug(LDAP_DEBUG_ANY,
+                                          "SASL BIND complete - ignoring empty credential response\n",
+                                          0, 0, 0);
+                                ber_bvfree( scred );
+                            } else {
+                                /* but server provided us with data! */
+                                LDAPDebug(LDAP_DEBUG_TRACE,
+                                          "SASL BIND complete but invalid because server responded with credentials - length [%u]\n",
+                                          scred->bv_len, 0, 0);
+                                ber_bvfree( scred );
+                                LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR,
+                                                  NULL, "Error during SASL handshake - invalid server credential response" );
+                                return( LDAP_LOCAL_ERROR );
+                            }
+                        }
+                        break;
+                }
+
+                /* perform the next step of the sasl bind */
+                do {
+                        LDAPDebug(LDAP_DEBUG_TRACE, "Doing client step %d of bind step %d for SASL/%s authentication\n",
+                                  clientstepnum, stepnum, (mech ? mech : "") );
+                        clientstepnum++;
+                        saslrc = sasl_client_step( ctx,
+                                (scred == NULL) ? NULL : scred->bv_val,
+                                (scred == NULL) ? 0 : scred->bv_len,
+                                &prompts,
+                                (const char **)&ccred.bv_val,
+                                &credlen );
+
+                        if( saslrc == SASL_INTERACT &&
+                            (callback)(ld, flags, defaults, prompts)
+                                                        != LDAP_SUCCESS ) {
+                                break;
+                        }
+                } while ( saslrc == SASL_INTERACT );
+
+                ccred.bv_len = credlen;
+                ber_bvfree( scred );
+
+                if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
+                        return( nsldapi_sasl_cvterrno( ld, saslrc, nsldapi_strdup( sasl_errdetail( ctx ) ) ) );
+                }
+        } while ( rc == LDAP_SASL_BIND_IN_PROGRESS );
+
+        if ( rc != LDAP_SUCCESS ) {
+                return( rc );
+        }
+
+        if ( saslrc != SASL_OK ) {
+                return( nsldapi_sasl_cvterrno( ld, saslrc, nsldapi_strdup( sasl_errdetail( ctx ) ) ) );
+        }
+
+        saslrc = sasl_getprop( ctx, SASL_USERNAME, (const void **) &sasl_username );
+        if ( (saslrc == SASL_OK) && sasl_username ) {
+                LDAPDebug(LDAP_DEBUG_TRACE, "SASL identity: %s\n", sasl_username, 0, 0);
+        }
+
+        saslrc = sasl_getprop( ctx, SASL_SSF, (const void **) &ssf );
+        if( saslrc == SASL_OK ) {
+                if( ssf && *ssf ) {
+                        LDAPDebug(LDAP_DEBUG_TRACE,
+                                "SASL install encryption, for SSF: %lu\n",
+                                (unsigned long) *ssf, 0, 0 );
+                        nsldapi_sasl_install( ld, NULL );
+                }
+        }
+
+        return( rc );
+}
+#endif /* LDAP_SASLIO_HOOKS */
+
+
+/*
+ * ldap_sasl_bind - authenticate to the ldap server.  The dn, mechanism,
+ * and credentials of the entry to which to bind are supplied. An LDAP
+ * error code is returned and if LDAP_SUCCESS is returned *msgidp is set
+ * to the id of the request initiated.
+ *
+ * Example:
+ *	struct berval	creds;
+ *	LDAPControl	**ctrls;
+ *	int		err, msgid;
+ *	... fill in creds with credentials ...
+ *	... fill in ctrls with server controls ...
+ *	err = ldap_sasl_bind( ld, "cn=manager, o=university of michigan, c=us",
+ *	    "mechanismname", &creds, ctrls, NULL, &msgid );
+ */
+int
+LDAP_CALL
+ldap_sasl_bind(
+    LDAP		*ld,
+    const char		*dn,
+    const char		*mechanism,
+    const struct berval	*cred,
+    LDAPControl		**serverctrls,
+    LDAPControl		**clientctrls,
+    int			*msgidp
+)
+{
+	BerElement	*ber;
+	int		rc, simple, msgid, ldapversion;
+
+	/*
+	 * The ldapv3 bind request looks like this:
+	 *	BindRequest ::= SEQUENCE {
+	 *		version		INTEGER,
+	 *		name		DistinguishedName,	 -- who
+	 *		authentication	CHOICE {
+	 *			simple		[0] OCTET STRING, -- passwd
+	 *			sasl		[3] SaslCredentials -- v3 only
+	 *		}
+	 *	}
+	 *	SaslCredentials ::= SEQUENCE {
+	 *		mechanism	LDAPString,
+	 * 		credentials	OCTET STRING
+	 *	}
+	 * all wrapped up in an LDAPMessage sequence.
+	 */
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_sasl_bind\n", 0, 0, 0 );
+	
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( LDAP_PARAM_ERROR );
+	}
+	
+	if ( msgidp == NULL ) {
+		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+		return( LDAP_PARAM_ERROR );
+	}
+	
+	if ( ( ld->ld_options & LDAP_BITOPT_RECONNECT ) != 0 ) {
+		nsldapi_handle_reconnect( ld );
+	}	
+
+	simple = ( mechanism == LDAP_SASL_SIMPLE );
+	ldapversion = NSLDAPI_LDAP_VERSION( ld );
+
+	/* only ldapv3 or higher can do sasl binds */
+	if ( !simple && ldapversion < LDAP_VERSION3 ) {
+		LDAP_SET_LDERRNO( ld, LDAP_NOT_SUPPORTED, NULL, NULL );
+		return( LDAP_NOT_SUPPORTED );
+	}
+
+	LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK );
+	msgid = ++ld->ld_msgid;
+	LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK );
+
+	if ( dn == NULL )
+		dn = "";
+
+	if ( ld->ld_cache_on && ld->ld_cache_bind != NULL ) {
+		LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK );
+		if ( (rc = (ld->ld_cache_bind)( ld, msgid, LDAP_REQ_BIND, dn,
+		    cred, LDAP_AUTH_SASL )) != 0 ) {
+			*msgidp = rc;
+			LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+			return( LDAP_SUCCESS );
+		}
+		LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+	}
+
+	/* create a message to send */
+	if (( rc = nsldapi_alloc_ber_with_options( ld, &ber ))
+	    != LDAP_SUCCESS ) {
+		return( rc );
+	}
+
+	/* fill it in */
+	if ( simple ) {		/* simple bind; works in LDAPv2 or v3 */
+		struct berval	tmpcred;
+
+		if ( cred == NULL ) {
+			tmpcred.bv_val = "";
+			tmpcred.bv_len = 0;
+			cred = &tmpcred;
+		}
+		rc = ber_printf( ber, "{it{isto}", msgid, LDAP_REQ_BIND,
+		    ldapversion, dn, LDAP_AUTH_SIMPLE, cred->bv_val,
+		    cred->bv_len );
+
+	} else {		/* SASL bind; requires LDAPv3 or better */
+		if ( cred == NULL || cred->bv_val == NULL || cred->bv_len == 0) {
+			rc = ber_printf( ber, "{it{ist{s}}", msgid,
+			    LDAP_REQ_BIND, ldapversion, dn, LDAP_AUTH_SASL,
+			    mechanism );
+		} else {
+			rc = ber_printf( ber, "{it{ist{so}}", msgid,
+			    LDAP_REQ_BIND, ldapversion, dn, LDAP_AUTH_SASL,
+			    mechanism, cred->bv_val,
+			    cred->bv_len );
+		}
+	}
+
+	if ( rc == -1 ) {
+		LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
+		ber_free( ber, 1 );
+		return( LDAP_ENCODING_ERROR );
+	}
+
+	if ( (rc = nsldapi_put_controls( ld, serverctrls, 1, ber ))
+	    != LDAP_SUCCESS ) {
+		ber_free( ber, 1 );
+		return( rc );
+	}
+
+	/* send the message */
+	rc = nsldapi_send_initial_request( ld, msgid, LDAP_REQ_BIND,
+		(char *)dn, ber );
+	*msgidp = rc;
+	return( rc < 0 ? LDAP_GET_LDERRNO( ld, NULL, NULL ) : LDAP_SUCCESS );
+}
+
+/*
+ * ldap_sasl_bind_s - bind to the ldap server using sasl authentication
+ * The dn, mechanism, and credentials of the entry to which to bind are
+ * supplied.  LDAP_SUCCESS is returned upon success, the ldap error code
+ * otherwise.
+ *
+ * Example:
+ *	struct berval	creds;
+ *	... fill in creds with credentials ...
+ *	ldap_sasl_bind_s( ld, "cn=manager, o=university of michigan, c=us",
+ *	    "mechanismname", &creds )
+ */
+int
+LDAP_CALL
+ldap_sasl_bind_s(
+    LDAP		*ld,
+    const char		*dn,
+    const char		*mechanism,
+    const struct berval	*cred,
+    LDAPControl		**serverctrls,
+    LDAPControl		**clientctrls,
+    struct berval	**servercredp
+)
+{
+        return ( nsldapi_sasl_bind_s( ld, dn, mechanism, cred,
+                 serverctrls, clientctrls, servercredp, NULL ) );
+}
+
+#ifdef LDAP_SASLIO_HOOKS 
+/*
+ * SASL Authentication Interface: ldap_sasl_interactive_bind_s
+ *
+ * This routine takes a DN, SASL mech list, and a SASL callback
+ * and performs the necessary sequencing to complete a SASL bind
+ * to the LDAP connection ld.  The user provided callback can
+ * use an optionally provided set of default values to complete
+ * any necessary interactions.
+ *
+ * Currently imposes the following restrictions:
+ *   A mech list must be provided
+ *   LDAP_SASL_INTERACTIVE mode requires a callback
+ */
+int
+LDAP_CALL
+ldap_sasl_interactive_bind_s( LDAP *ld, const char *dn,
+        const char *saslMechanism,
+        LDAPControl **sctrl, LDAPControl **cctrl, unsigned flags,
+        LDAP_SASL_INTERACT_PROC *callback, void *defaults )
+{
+        return ldap_sasl_interactive_bind_ext_s( ld, dn, 
+                saslMechanism, sctrl, cctrl, flags, callback,
+                defaults, NULL );
+}
+
+/*
+ * ldap_sasl_interactive_bind_ext_s
+ *
+ * This function extends ldap_sasl_interactive_bind_s by allowing
+ * controls received from the server to be returned as rctrl. The
+ * caller must pass in a valid LDAPControl** pointer and free the
+ * array of controls when finished with them e.g.
+ * LDAPControl **retctrls = NULL;
+ * ...
+ * ldap_sasl_interactive_bind_ext_s(ld, ...., &retctrls);
+ * ...
+ * ldap_controls_free(retctrls);
+ * Only the controls from the server during the last bind step are returned -
+ * intermediate controls (if any, usually not) are discarded.
+ */
+int
+LDAP_CALL
+ldap_sasl_interactive_bind_ext_s( LDAP *ld, const char *dn,
+        const char *saslMechanism,
+        LDAPControl **sctrl, LDAPControl **cctrl, unsigned flags,
+        LDAP_SASL_INTERACT_PROC *callback, void *defaults, LDAPControl ***rctrl )
+{
+#ifdef LDAP_SASLIO_GET_MECHS_FROM_SERVER
+        char *smechs;
+#endif
+        int rc;
+
+        LDAPDebug( LDAP_DEBUG_TRACE, "ldap_sasl_interactive_bind_s\n", 0, 0, 0 );
+
+        if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+                return( LDAP_PARAM_ERROR );
+        }
+
+        if ((flags == LDAP_SASL_INTERACTIVE) && (callback == NULL)) {
+                return( LDAP_PARAM_ERROR );
+        }
+
+        LDAP_MUTEX_LOCK(ld, LDAP_SASL_LOCK );
+
+        if( saslMechanism == NULL || *saslMechanism == '\0' ) {
+#ifdef LDAP_SASLIO_GET_MECHS_FROM_SERVER
+                rc = nsldapi_get_sasl_mechs( ld, &smechs );
+                if( rc != LDAP_SUCCESS ) {
+                        LDAP_MUTEX_UNLOCK(ld, LDAP_SASL_LOCK );
+                        return( rc );
+                }
+                saslMechanism = smechs;
+#else
+                LDAP_MUTEX_UNLOCK(ld, LDAP_SASL_LOCK );
+                return( LDAP_PARAM_ERROR );
+#endif /* LDAP_SASLIO_GET_MECHS_FROM_SERVER */
+        }
+
+        rc = nsldapi_sasl_do_bind( ld, dn, saslMechanism,
+                        flags, callback, defaults, sctrl, cctrl, rctrl);
+
+        LDAP_MUTEX_UNLOCK(ld, LDAP_SASL_LOCK );
+        return( rc );
+}
+#else /* LDAP_SASLIO_HOOKS */
+/* stubs for platforms that do not support SASL */
+int
+LDAP_CALL
+ldap_sasl_interactive_bind_s( LDAP *ld, const char *dn,
+        const char *saslMechanism,
+        LDAPControl **sctrl, LDAPControl **cctrl, unsigned flags,
+        LDAP_SASL_INTERACT_PROC *callback, void *defaults )
+{
+  return LDAP_SUCCESS;
+}
+
+int
+LDAP_CALL
+ldap_sasl_interactive_bind_ext_s( LDAP *ld, const char *dn,
+        const char *saslMechanism,
+        LDAPControl **sctrl, LDAPControl **cctrl, unsigned flags,
+        LDAP_SASL_INTERACT_PROC *callback, void *defaults, LDAPControl ***rctrl )
+{
+  return LDAP_SUCCESS;
+}
+#endif /* LDAP_SASLIO_HOOKS */
+
+
+/* returns an LDAP error code that indicates if parse succeeded or not */
+int
+LDAP_CALL
+ldap_parse_sasl_bind_result(
+    LDAP		*ld,
+    LDAPMessage		*res,
+    struct berval	**servercredp,
+    int			freeit
+)
+{
+	BerElement	ber;
+	int		rc, err;
+    ber_int_t	along;
+	ber_len_t	len;
+	char		*m, *e;
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_parse_sasl_bind_result\n", 0, 0, 0 );
+
+	/*
+	 * the ldapv3 SASL bind response looks like this:
+	 *
+	 *	BindResponse ::= [APPLICATION 1] SEQUENCE {
+	 *		COMPONENTS OF LDAPResult,
+	 *		serverSaslCreds [7] OCTET STRING OPTIONAL
+	 *	}
+	 *
+	 * all wrapped up in an LDAPMessage sequence.
+	 */
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) ||
+	    !NSLDAPI_VALID_LDAPMESSAGE_BINDRESULT_POINTER( res )) {
+		return( LDAP_PARAM_ERROR );
+	}
+
+	/* only ldapv3 or higher can do sasl binds */
+	if ( NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION3 ) {
+		LDAP_SET_LDERRNO( ld, LDAP_NOT_SUPPORTED, NULL, NULL );
+		return( LDAP_NOT_SUPPORTED );
+	}
+
+	if ( servercredp != NULL ) {
+		*servercredp = NULL;
+	}
+
+	ber = *(res->lm_ber);	/* struct copy */
+
+	/* skip past message id, matched dn, error message ... */
+	rc = ber_scanf( &ber, "{iaa}", &along, &m, &e );
+
+	if ( rc != LBER_ERROR &&
+	    ber_peek_tag( &ber, &len ) == LDAP_TAG_SASL_RES_CREDS ) {
+		rc = ber_get_stringal( &ber, servercredp );
+	}
+
+	if ( freeit ) {
+		ldap_msgfree( res );
+	}
+
+	if ( rc == LBER_ERROR ) {
+		err = LDAP_DECODING_ERROR;
+	} else {
+		err = (int) along;
+	}
+
+	LDAP_SET_LDERRNO( ld, err, m, e );
+	/* this is a little kludge for the 3.0 Barracuda/hammerhead relese */
+	/* the docs state that the return is either LDAP_DECODING_ERROR */
+	/* or LDAP_SUCCESS.  Here we match the docs...  it's cleaner in 3.1 */
+
+	if ( LDAP_DECODING_ERROR == err ) {
+		return (LDAP_DECODING_ERROR);
+	} else {
+		return( LDAP_SUCCESS );
+	}
+}
+
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/saslio.c
@@ -0,0 +1,635 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Sun LDAP C SDK.
+ *
+ * The Initial Developer of the Original Code is Sun Microsystems, Inc.
+ *
+ * Portions created by Sun Microsystems, Inc are Copyright (C) 2005
+ * Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifdef LDAP_SASLIO_HOOKS
+#include <assert.h>
+#include "ldap-int.h"
+#include "../liblber/lber-int.h"
+#include <sasl.h>
+/* Should be pulled in from lber-int.h */
+#define READBUFSIZ	8192
+
+#define SEARCH_TIMEOUT_SECS	120
+#define NSLDAPI_SM_BUF	128
+
+/*
+ * Data structures:
+ */
+
+/* data structure that populates the I/O callback socket-specific arg. */
+typedef struct lextiof_socket_private {
+	struct ldap_x_ext_io_fns sess_io_fns; /* the saved layered ld fns from the layer we are "pushing" */
+	struct lber_x_ext_io_fns sock_io_fns; /* the saved layered ber fns from the layer we are "pushing" */
+	sasl_conn_t     *sasl_ctx;     /* the sasl context - pointer to the one from the connection */
+	char            *sb_sasl_ibuf; /* sasl decrypted input buffer */
+	char            *sb_sasl_iptr; /* current location in buffer */
+	int             sb_sasl_bfsz;  /* Alloc'd size of input buffer */
+	int             sb_sasl_ilen;  /* remaining length to process */
+	LDAP            *ld;           /* used to set errno */
+	Sockbuf         *sb;           /* pointer to our associated sockbuf */
+} SASLIOSocketArg;
+
+static void
+destroy_SASLIOSocketArg(SASLIOSocketArg** sockarg)
+{
+	if (sockarg && *sockarg) {
+		NSLDAPI_FREE((*sockarg)->sb_sasl_ibuf);
+		NSLDAPI_FREE((*sockarg));
+		*sockarg = NULL;
+	}
+}
+
+static SASLIOSocketArg*
+new_SASLIOSocketArg(sasl_conn_t *ctx, int bufsiz, LDAP *ld, Sockbuf *sb)
+{
+	SASLIOSocketArg *sockarg = NULL;
+
+	if (bufsiz <= 0) {
+		return sockarg;
+	}
+
+	sockarg = (SASLIOSocketArg*)NSLDAPI_CALLOC(1, sizeof(SASLIOSocketArg));
+	if (sockarg) {
+		sockarg->sasl_ctx = ctx;
+		sockarg->sb_sasl_ibuf = NSLDAPI_MALLOC(bufsiz);
+		if (!sockarg->sb_sasl_ibuf) {
+			destroy_SASLIOSocketArg(&sockarg);
+			return sockarg;
+		}
+		sockarg->sb_sasl_iptr = NULL;
+		sockarg->sb_sasl_bfsz = bufsiz;
+		sockarg->sb_sasl_ilen = 0;
+		sockarg->ld           = ld;
+		sockarg->sb           = sb;
+	}
+
+	return sockarg;
+}
+
+/*
+ * SASL Dependent routines
+ *
+ * SASL security and integrity options are supported through the
+ * use of the extended I/O functionality.  Because the extended
+ * I/O functions may already be in use prior to enabling encryption,
+ * when SASL encryption si enabled, these routine interpose themselves
+ * over the exitng extended I/O routines and add an additional level
+ * of indirection.
+ *  IE: Before SASL:  client->libldap->lber->extio
+ *      After  SASL:  client->libldap->lber->saslio->extio
+ * Any extio function are stilled used for the raw i/O [IE prldap]
+ * but SASL will decrypt before passing to lber.
+ * SASL cannot decrypt a stream so full packaets must be read
+ * before proceeding.
+ */
+
+/*
+ * Get the 4 octet header [size] for a sasl encrypted buffer.
+ * See RFC222 [section 3].
+ */
+static int
+nsldapi_sasl_pktlen( char *buf, int maxbufsize )
+{
+        int     size;
+
+#if defined( _WINDOWS ) || defined( _WIN32 )
+        size = ntohl(*(u_long *)buf);
+#else
+        size = ntohl(*(uint32_t *)buf);
+#endif
+        if ( size < 0 || size > maxbufsize ) {
+                return (-1 );
+        }
+
+        return( size + 4 ); /* include the first 4 bytes */
+}
+
+/*
+ * SASL encryption routines
+ */
+
+static int
+nsldapi_sasl_read( int s, void *buf, int  len,
+	struct lextiof_socket_private *arg)
+{
+	LDAP		*ld;
+	const char	*dbuf;
+	char		*cp;
+	int		ret;
+	unsigned	dlen, blen;
+   
+	ld = (LDAP *)arg->ld;
+
+	/* Is there anything left in the existing buffer? */
+	if ((ret = arg->sb_sasl_ilen) > 0) {
+		ret = (ret > len ? len : ret);
+		SAFEMEMCPY( buf, arg->sb_sasl_iptr, ret );
+		if (ret == arg->sb_sasl_ilen) {
+			arg->sb_sasl_ilen = 0;
+			arg->sb_sasl_iptr = NULL;
+		} else {
+			arg->sb_sasl_ilen -= ret;
+			arg->sb_sasl_iptr += ret;
+		}
+		return( ret );
+	}
+
+	/* buffer is empty - fill it */
+	cp = arg->sb_sasl_ibuf;
+	dlen = 0;
+	
+	/* Read the length of the packet */
+	while ( dlen < 4 ) {
+		if (arg->sock_io_fns.lbextiofn_read != NULL) {
+			ret = arg->sock_io_fns.lbextiofn_read(
+				s, cp, 4 - dlen,
+				arg->sock_io_fns.lbextiofn_socket_arg);
+		} else {
+			ret = read( s, cp, 4 - dlen );
+		}
+#ifdef EINTR
+		if ( ( ret < 0 ) && ( LDAP_GET_ERRNO(ld) == EINTR ) )
+			continue;
+#endif
+		if ( ret <= 0 )
+			return( ret );
+
+		cp += ret;
+		dlen += ret;
+	}
+
+	blen = 4;
+
+	ret = nsldapi_sasl_pktlen( arg->sb_sasl_ibuf, arg->sb_sasl_bfsz );
+	if (ret < 0) {
+		LDAP_SET_ERRNO(ld, EIO);
+		return( -1 );
+	}
+	dlen = ret - dlen;
+
+	/* read the rest of the encrypted packet */
+	while ( dlen > 0 ) {
+		if (arg->sock_io_fns.lbextiofn_read != NULL) {
+			ret = arg->sock_io_fns.lbextiofn_read(
+				s, cp, dlen,
+				arg->sock_io_fns.lbextiofn_socket_arg);
+		} else {
+			ret = read( s, cp, dlen );
+		}
+
+#ifdef EINTR
+		if ( ( ret < 0 ) && ( LDAP_GET_ERRNO(ld) == EINTR ) )
+			continue;
+#endif
+		if ( ret <= 0 )
+			return( ret );
+
+		cp += ret;
+		blen += ret;
+		dlen -= ret;
+   	}
+
+	/* Decode the packet */
+	ret = sasl_decode( arg->sasl_ctx,
+			   arg->sb_sasl_ibuf, blen,
+			   &dbuf, &dlen);
+	if ( ret != SASL_OK ) {
+		/* sb_sasl_read: failed to decode packet, drop it, error */
+		arg->sb_sasl_iptr = NULL;
+		arg->sb_sasl_ilen = 0;
+		LDAP_SET_ERRNO(ld, EIO);
+		return( -1 );
+	}
+	
+	/* copy decrypted packet to the input buffer */
+	SAFEMEMCPY( arg->sb_sasl_ibuf, dbuf, dlen );
+	arg->sb_sasl_iptr = arg->sb_sasl_ibuf;
+	arg->sb_sasl_ilen = dlen;
+
+	ret = (dlen > (unsigned) len ? len : dlen);
+	SAFEMEMCPY( buf, arg->sb_sasl_iptr, ret );
+	if (ret == arg->sb_sasl_ilen) {
+		arg->sb_sasl_ilen = 0;
+		arg->sb_sasl_iptr = NULL;
+	} else {
+		arg->sb_sasl_ilen -= ret;
+		arg->sb_sasl_iptr += ret;
+	}
+	return( ret );
+}
+
+static int
+nsldapi_sasl_write( int s, const void *buf, int  len,
+	struct lextiof_socket_private *arg)
+{
+	int			ret = 0;
+	const char	*obuf, *optr, *cbuf = (const char *)buf;
+	unsigned	olen, clen, tlen = 0;
+	unsigned	*maxbuf; 
+	
+	ret = sasl_getprop(arg->sasl_ctx, SASL_MAXOUTBUF,
+					   (const void **)&maxbuf);
+	if ( ret != SASL_OK ) {
+		/* just a sanity check, should never happen */
+		return( -1 );
+	}
+	
+	while (len > 0) {
+		clen = (len > *maxbuf) ? *maxbuf : len;
+		/* encode the next packet. */
+		ret = sasl_encode( arg->sasl_ctx, cbuf, clen, &obuf, &olen);
+		if ( ret != SASL_OK ) {
+			/* XXX Log error? "sb_sasl_write: failed to encode packet..." */
+			return( -1 );
+		}
+		/* Write everything now, buffer is only good until next sasl_encode */
+		optr = obuf;
+		while (olen > 0) {
+			if (arg->sock_io_fns.lbextiofn_write != NULL) {
+				ret = arg->sock_io_fns.lbextiofn_write(
+					s, optr, olen,
+					arg->sock_io_fns.lbextiofn_socket_arg);
+			} else {
+				ret = write( s, optr, olen);
+			}
+			if ( ret < 0 )
+				return( ret );
+			optr += ret;
+			olen -= ret;
+		}
+		len -= clen;
+		cbuf += clen;
+		tlen += clen;
+	}
+	return( tlen );
+}
+
+/*
+ * What's all this then?
+ * First, take a look at os-ip.c:nsldapi_add_to_cb_pollfds().  When a new descriptor is
+ * added to the pollfds array, the lpoll_socketarg field is initialized to the value from
+ * the socketarg field - sb->sb_ext_io_fns.lbextiofn_socket_arg.  In our case, since we
+ * override this with our sasl data (see below nsldapi_sasl_install), we need to restore
+ * the previous value so that the layer below us (i.e. prldap) can use the lpoll_socketarg
+ * which it sets.
+ * So how do which know which fds[i] is a "sasl" fd?
+ * We initialize the lextiof_session_private *arg (see nsldapi_sasl_install) to point to
+ * the socket_private data in sb->sb_ext_io_fns.lbextiofn_socket_arg for "sasl" sockets,
+ * which is then used to initialize lpoll_socketarg (see above).
+ * So, if the arg which gets passed into nsldapi_sasl_poll is the same as the
+ * fds[i].lpoll_socketarg, we know it is a "sasl" socket and we need to "pop" the sasl
+ * layer.  We do this by replacing lpoll_socketarg with the one we saved when we "pushed"
+ * the sasl layer.
+ * So why the loop to restore the sasl lpoll_socketarg?
+ * The lower layer only uses lpoll_socketarg during poll().  See ldappr-io.c:prldap_poll()
+ * for more information about how that works.  However, after the polling is done, there
+ * is some special magic in os-ip.c in the functions nsldapi_add_to_cb_pollfds(),
+ * nsldapi_clear_from_cb_pollfds(), and nsldapi_find_in_cb_pollfds() to find the correct
+ * Sockbuf to operate on.  This is the macro NSLDAPI_CB_POLL_MATCH().  For the extended
+ * io function callbacks to work correctly, it is not sufficient to say that the file
+ * descriptor in the Sockbuf matches the one that poll says has activity - we also need
+ * to match the lpoll_socketarg with the sb->sb_ext_io_fns.lbextiofn_socket_arg to make
+ * sure this really is the Sockbuf we want to use.  So we have to restore the
+ * lpoll_socketarg with the original one.
+ * Why have origarg and staticorigarg?
+ * To avoid malloc.  The sizeof staticorigarg should be large enough to accomodate almost
+ * all clients without incurring too much additional overhead.  However, if we need more
+ * room, origarg will grow to nfds.  If this proves to be inadequate, the size of the
+ * staticorigarg is a good candidate for a #define set by configure.
+ */
+static int
+nsldapi_sasl_poll(
+	LDAP_X_PollFD fds[], int nfds, int timeout,
+	struct lextiof_session_private *arg ) 
+{
+	LDAP_X_EXTIOF_POLL_CALLBACK *origpoll; /* poll fn from the pushed layer */
+	struct lextiof_session_private *origsess = NULL; /* session arg from the pushed layer */
+	SASLIOSocketArg **origarg = NULL; /* list of saved original socket args */
+	SASLIOSocketArg *staticorigarg[1024]; /* default list to avoid malloc */
+	int origargsize = sizeof(staticorigarg)/sizeof(staticorigarg[0]);
+	int rc = -1; /* the return code - -1 means failure */
+
+	if (arg == NULL) { /* should not happen */
+		return( rc );
+	}
+
+	origarg = staticorigarg;
+	/* if the static array is not large enough, alloc a dynamic one */
+	if (origargsize < nfds) {
+		origarg = (SASLIOSocketArg **)NSLDAPI_MALLOC(nfds*sizeof(SASLIOSocketArg *));
+	}
+
+	if (fds && nfds > 0) {
+		int i;
+		for(i = 0; i < nfds; i++) {
+			/* save the original socket arg */
+			origarg[i] = fds[i].lpoll_socketarg;
+			if (arg == (struct lextiof_session_private *)fds[i].lpoll_socketarg) {
+				/* lpoll_socketarg is a sasl socket arg - we need to replace it
+				   with the one from the layer we pushed (i.e. prldap) */
+				SASLIOSocketArg *sockarg = (SASLIOSocketArg *)fds[i].lpoll_socketarg;
+				/* reset to pushed layer's socket arg */
+				fds[i].lpoll_socketarg = sockarg->sock_io_fns.lbextiofn_socket_arg;
+				/* grab the pushed layers' poll fn and its session arg */
+				if (!origsess) {
+					origpoll = sockarg->sess_io_fns.lextiof_poll;
+					origsess = sockarg->sess_io_fns.lextiof_session_arg;
+				}
+			}
+		}
+	}
+
+	if (origsess == NULL) { /* should not happen */
+		goto done;
+	}
+
+	/* call the "real" poll function */
+	rc = origpoll( fds, nfds, timeout, origsess );
+
+	/* reset the lpoll_socketarg values to their original values because
+	   they must match what's in sb->iofns->lbextiofn_socket_arg in order
+	   for NSLDAPI_CB_POLL_MATCH to work - see os-ip.c */
+	if (fds && nfds > 0) {
+		int i;
+		for(i = 0; i < nfds; i++) {
+			if ((SASLIOSocketArg *)arg == origarg[i]) {
+				fds[i].lpoll_socketarg = origarg[i];
+			}
+		}
+	}
+
+done:
+	/* if we had to use a dynamic array, free it */
+	if (origarg != staticorigarg) {
+		NSLDAPI_FREE(origarg);
+	}
+
+	return rc;
+}
+
+int
+nsldapi_sasl_open( LDAP *ld, LDAPConn *lconn, sasl_conn_t **ctx, sasl_ssf_t ssf )
+{
+        int saslrc;
+        char *host = NULL;
+
+        if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+                LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL, NULL );
+                return( LDAP_LOCAL_ERROR );
+        }
+
+        if ( lconn == NULL ) {
+                if ( ld->ld_defconn == NULL ||
+                     ld->ld_defconn->lconn_status != LDAP_CONNST_CONNECTED) {
+                        int rc = nsldapi_open_ldap_defconn( ld );
+                        if( rc < 0 )  {
+                                return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+                        }
+                }
+                lconn = ld->ld_defconn;
+        }
+
+        /* need to clear out the old context for this connection, if any */
+        /* client may have re-bind-ed this connection without closing first */
+        if (lconn->lconn_sasl_ctx) {
+            sasl_dispose(&lconn->lconn_sasl_ctx);
+            lconn->lconn_sasl_ctx = NULL;
+        }
+
+        if ( 0 != ldap_get_option( ld, LDAP_OPT_HOST_NAME, &host ) ) {
+                LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL, NULL );
+                return( LDAP_LOCAL_ERROR );
+        }
+
+        saslrc = sasl_client_new( "ldap", host,
+                NULL, NULL, /* iplocalport, ipremoteport - use defaults */
+                NULL, 0, ctx );
+        ldap_memfree(host);
+
+        if ( (saslrc != SASL_OK) || (!*ctx) ) {
+                return( nsldapi_sasl_cvterrno( ld, saslrc, NULL ) );
+        }
+
+        if( ssf ) {
+                sasl_ssf_t extprops;
+                memset(&extprops, 0L, sizeof(extprops));
+                extprops = ssf;
+
+                (void) sasl_setprop( *ctx, SASL_SSF_EXTERNAL,
+                        (void *) &extprops );
+        }
+
+        /* (re)set security properties */
+        sasl_setprop( *ctx, SASL_SEC_PROPS, &ld->ld_sasl_secprops );
+
+        /* set the connection context */
+        lconn->lconn_sasl_ctx = *ctx;
+
+        return( LDAP_SUCCESS );
+}
+
+static int
+nsldapi_sasl_close( struct lextiof_socket_private *arg )
+{
+	/* undo function pointer interposing */
+	ldap_set_option( arg->ld, LDAP_X_OPT_EXTIO_FN_PTRS, &arg->sess_io_fns );
+	/* have to do this separately to make sure the socketarg is set correctly */
+	ber_sockbuf_set_option( arg->sb,
+							LBER_SOCKBUF_OPT_EXT_IO_FNS,
+							(void *)&arg->sock_io_fns );
+
+	destroy_SASLIOSocketArg(&arg);
+	return( LDAP_SUCCESS );
+}
+
+static int
+nsldapi_sasl_close_socket(int s, struct lextiof_socket_private *arg ) 
+{
+	LDAP_X_EXTIOF_CLOSE_CALLBACK *origclose;
+	struct lextiof_socket_private *origsock;
+
+	if (arg == NULL) {
+		return( -1 );
+	}
+
+	origclose = arg->sess_io_fns.lextiof_close;
+	origsock = arg->sock_io_fns.lbextiofn_socket_arg;
+
+	/* undo SASL */
+	nsldapi_sasl_close( arg );
+	arg = NULL;
+	/* arg is destroyed at this point - do not use it */
+
+	if (origclose )
+		return ( origclose( s, origsock ) );
+	else {
+		/* This is a copy of nsldapi_os_closesocket()
+		 * from os-ip.c. It is declared static there,
+		 * hence the copy of it.
+		 */
+	        int     rc;
+
+#ifdef NSLDAPI_AVOID_OS_SOCKETS
+		rc = -1;
+#else /* NSLDAPI_AVOID_OS_SOCKETS */
+#ifdef _WINDOWS
+		rc = closesocket( s );
+#else /* _WINDOWS */
+		rc = close( s );
+#endif /* _WINDOWS */
+#endif /* NSLDAPI_AVOID_OS_SOCKETS */
+		return( rc );
+	}
+		
+}
+
+/*
+ * install encryption routines if security has been negotiated
+ */
+int
+nsldapi_sasl_install( LDAP *ld, LDAPConn *lconn )
+{
+        struct lber_x_ext_io_fns        fns;
+        struct ldap_x_ext_io_fns        iofns;
+        sasl_security_properties_t      *secprops;
+        int     rc, value;
+        int     bufsiz;
+        Sockbuf *sb = NULL;
+        sasl_conn_t *ctx = NULL;
+        SASLIOSocketArg *sockarg = NULL;
+
+        if ( lconn == NULL ) {
+                lconn = ld->ld_defconn;
+                if ( lconn == NULL ) {
+                        return( LDAP_LOCAL_ERROR );
+                }
+        }
+        if ( (sb = lconn->lconn_sb) == NULL ) {
+                return( LDAP_LOCAL_ERROR );
+        }
+        rc = ber_sockbuf_get_option( sb,
+                        LBER_SOCKBUF_OPT_TO_FILE_ONLY,
+                        (void *) &value);
+        if (rc != 0 || value != 0) {
+                return( LDAP_LOCAL_ERROR );
+        }
+
+        /* the sasl context in the lconn must have been set prior to this */
+        ctx = lconn->lconn_sasl_ctx;
+        rc = sasl_getprop( ctx, SASL_SEC_PROPS,
+                           (const void **)&secprops );
+        if (rc != SASL_OK)
+                return( LDAP_LOCAL_ERROR );
+        bufsiz = secprops->maxbufsize;
+        if (bufsiz <= 0) {
+                return( LDAP_LOCAL_ERROR );
+        }
+
+        /* create our socket specific context */
+        sockarg = new_SASLIOSocketArg(ctx, bufsiz, ld, sb);
+        if (!sockarg) {
+                return( LDAP_LOCAL_ERROR );
+        }
+
+        /* save a copy of the existing io fns and the session arg */
+        memset( &sockarg->sess_io_fns, 0, LDAP_X_EXTIO_FNS_SIZE );
+        sockarg->sess_io_fns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE;
+        rc = ldap_get_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS,
+                              &sockarg->sess_io_fns );
+        if (rc != 0) {
+                destroy_SASLIOSocketArg(&sockarg);
+                return( LDAP_LOCAL_ERROR );
+        }
+
+        /* save a copy of the existing ber io fns and the socket arg */
+        memset( &sockarg->sock_io_fns, 0, LBER_X_EXTIO_FNS_SIZE );
+        sockarg->sock_io_fns.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE;
+        rc = ber_sockbuf_get_option( sb,
+                        LBER_SOCKBUF_OPT_EXT_IO_FNS,
+                        (void *)&sockarg->sock_io_fns);
+        if (rc != 0) {
+                destroy_SASLIOSocketArg(&sockarg);
+                return( LDAP_LOCAL_ERROR );
+        }
+
+	/* Always set the ext io close fn pointer to ensure we
+	 * clean up our sockarg context */
+	memset( &iofns, 0, sizeof(iofns));
+	/* first, copy struct - sets defaults */
+	iofns = sockarg->sess_io_fns;
+	iofns.lextiof_close = nsldapi_sasl_close_socket;
+	iofns.lextiof_session_arg = sockarg; /* needed for close and poll */
+
+        /* Set new values for the other ext io funcs if there are any -
+           when using the native io fns (as opposed to prldap) there
+           won't be any */
+        if (  sockarg->sess_io_fns.lextiof_read != NULL ||
+              sockarg->sess_io_fns.lextiof_write != NULL ||
+              sockarg->sess_io_fns.lextiof_poll != NULL ||
+              sockarg->sess_io_fns.lextiof_connect != NULL ) {
+		/* next, just reset those functions we want to override */
+                iofns.lextiof_read = nsldapi_sasl_read;
+                iofns.lextiof_write = nsldapi_sasl_write;
+                iofns.lextiof_poll = nsldapi_sasl_poll;
+        }
+
+	/* set the ext io funcs */
+	rc = ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, &iofns );
+	if (rc != 0) {
+		/* frees everything and resets fns above */
+		nsldapi_sasl_close(sockarg);
+		return( LDAP_LOCAL_ERROR );
+	}
+
+        /* set the new ber io funcs and socket arg */
+        (void) memset( &fns, 0, LBER_X_EXTIO_FNS_SIZE);
+        fns.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE;
+        fns.lbextiofn_read = nsldapi_sasl_read;
+        fns.lbextiofn_write = nsldapi_sasl_write;
+        fns.lbextiofn_socket_arg = sockarg;
+        rc = ber_sockbuf_set_option( sb,
+                        LBER_SOCKBUF_OPT_EXT_IO_FNS,
+                        (void *)&fns);
+        if (rc != 0) {
+                /* frees everything and resets fns above */
+                nsldapi_sasl_close(sockarg);
+                return( LDAP_LOCAL_ERROR );
+        }
+
+        return( LDAP_SUCCESS );
+}
+
+#endif
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/sbind.c
@@ -0,0 +1,214 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ *  Copyright (c) 1993 Regents of the University of Michigan.
+ *  All rights reserved.
+ */
+/*
+ *  sbind.c
+ */
+
+#if 0
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1993 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+static int simple_bind_nolock( LDAP *ld, const char *dn, const char *passwd,
+	int unlock_permitted );
+
+/*
+ * ldap_simple_bind - bind to the ldap server.  The dn and
+ * password of the entry to which to bind are supplied.  The message id
+ * of the request initiated is returned.
+ *
+ * Example:
+ *	ldap_simple_bind( ld, "cn=manager, o=university of michigan, c=us",
+ *	    "secret" )
+ */
+
+int
+LDAP_CALL
+ldap_simple_bind( LDAP *ld, const char *dn, const char *passwd )
+{
+	int	rc;
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_simple_bind\n", 0, 0, 0 );
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( LDAP_PARAM_ERROR );
+	}
+
+	if ( ( ld->ld_options & LDAP_BITOPT_RECONNECT ) != 0 ) {
+		nsldapi_handle_reconnect( ld );
+	}
+
+	rc = simple_bind_nolock( ld, dn, passwd, 1 );
+
+	return( rc );
+}
+
+
+static int
+simple_bind_nolock( LDAP *ld, const char *dn, const char *passwd,
+    int unlock_permitted )
+{
+	BerElement	*ber;
+	int		rc, msgid;
+
+	/*
+	 * The bind request looks like this:
+	 *	BindRequest ::= SEQUENCE {
+	 *		version		INTEGER,
+	 *		name		DistinguishedName,	 -- who
+	 *		authentication	CHOICE {
+	 *			simple		[0] OCTET STRING -- passwd
+	 *		}
+	 *	}
+	 * all wrapped up in an LDAPMessage sequence.
+	 */
+
+	LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK );
+	msgid = ++ld->ld_msgid;
+	LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK );
+
+	if ( dn == NULL )
+		dn = "";
+	if ( passwd == NULL )
+		passwd = "";
+
+	if ( ld->ld_cache_on && ld->ld_cache_bind != NULL ) {
+		struct berval	bv;
+
+		bv.bv_val = (char *)passwd;
+		bv.bv_len = strlen( passwd );
+		/* if ( unlock_permitted ) LDAP_MUTEX_UNLOCK( ld ); */
+		LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK );
+		rc = (ld->ld_cache_bind)( ld, msgid, LDAP_REQ_BIND, dn, &bv,
+		    LDAP_AUTH_SIMPLE );
+		LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+		/* if ( unlock_permitted ) LDAP_MUTEX_LOCK( ld ); */
+		if ( rc != 0 ) {
+			return( rc );
+		}
+	}
+
+	/* create a message to send */
+	if (( rc = nsldapi_alloc_ber_with_options( ld, &ber ))
+	    != LDAP_SUCCESS ) {
+		return( -1 );
+	}
+
+	/* fill it in */
+	if ( ber_printf( ber, "{it{ists}", msgid, LDAP_REQ_BIND,
+	    NSLDAPI_LDAP_VERSION( ld ), dn, LDAP_AUTH_SIMPLE, passwd ) == -1 ) {
+		LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
+		ber_free( ber, 1 );
+		return( -1 );
+	}
+
+	if ( nsldapi_put_controls( ld, NULL, 1, ber ) != LDAP_SUCCESS ) {
+		ber_free( ber, 1 );
+		return( -1 );
+	}
+
+	/* send the message */
+	return( nsldapi_send_initial_request( ld, msgid, LDAP_REQ_BIND,
+		(char *)dn, ber ));
+}
+
+
+/*
+ * ldap_simple_bind - bind to the ldap server using simple
+ * authentication.  The dn and password of the entry to which to bind are
+ * supplied.  LDAP_SUCCESS is returned upon success, the ldap error code
+ * otherwise.
+ *
+ * Example:
+ *	ldap_simple_bind_s( ld, "cn=manager, o=university of michigan, c=us",
+ *	    "secret" )
+ */
+int
+LDAP_CALL
+ldap_simple_bind_s( LDAP *ld, const char *dn, const char *passwd )
+{
+	int		msgid;
+	LDAPMessage	*result;
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_simple_bind_s\n", 0, 0, 0 );
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( LDAP_PARAM_ERROR );
+	}
+
+	if ( (msgid = ldap_simple_bind( ld, dn, passwd )) == -1 )
+		return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+
+	if ( ldap_result( ld, msgid, 1, (struct timeval *) 0, &result ) == -1 )
+		return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+
+	return( ldap_result2error( ld, result, 1 ) );
+}
+
+void nsldapi_handle_reconnect( LDAP *ld )
+{
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_handle_reconnect\n", 0, 0, 0 );
+	
+	/*
+	 * if the default connection has been lost and is now marked dead,
+	 * dispose of the default connection so it will get re-established.
+	 *
+	 * if not, clear the bind DN and status to ensure that we don't
+	 * report the wrong bind DN to a different thread while waiting
+	 * for our bind result to return from the server.
+	 */
+	LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK );
+	if ( NULL != ld->ld_defconn ) {
+	    if ( LDAP_CONNST_DEAD == ld->ld_defconn->lconn_status ) {
+			nsldapi_free_connection( ld, ld->ld_defconn, NULL, NULL, 1, 0 );
+			ld->ld_defconn = NULL;
+	    } else if ( ld->ld_defconn->lconn_binddn != NULL ) {
+			NSLDAPI_FREE( ld->ld_defconn->lconn_binddn );
+			ld->ld_defconn->lconn_binddn = NULL;
+			ld->ld_defconn->lconn_bound = 0;
+	    }
+	}
+	LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/search.c
@@ -0,0 +1,1022 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ *  Copyright (c) 1990 Regents of the University of Michigan.
+ *  All rights reserved.
+ */
+/*
+ *  search.c
+ */
+
+#if 0
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+static int nsldapi_timeval2ldaplimit( struct timeval *timeoutp,
+	int defaultvalue );
+static int nsldapi_search( LDAP *ld, const char *base, int scope,
+	const char *filter, char **attrs, int attrsonly,
+	LDAPControl **serverctrls, LDAPControl **clientctrls,
+	int timelimit, int sizelimit, int *msgidp );
+static char *find_right_paren( char *s );
+static char *put_complex_filter( BerElement *ber, char *str,
+	unsigned long tag, int not );
+static int put_filter( BerElement *ber, char *str );
+static int unescape_filterval( char *str );
+static int hexchar2int( char c );
+static int is_valid_attr( char *a );
+static int put_simple_filter( BerElement *ber, char *str );
+static int put_substring_filter( BerElement *ber, char *type,
+	char *str );
+static int put_filter_list( BerElement *ber, char *str );
+static int nsldapi_search_s( LDAP *ld, const char *base, int scope, 
+	const char *filter, char **attrs, int attrsonly,
+	LDAPControl **serverctrls, LDAPControl **clientctrls,
+	struct timeval *localtimeoutp, int timelimit, int sizelimit,
+	LDAPMessage **res );
+
+/*
+ * ldap_search - initiate an ldap search operation.  Parameters:
+ *
+ *	ld		LDAP descriptor
+ *	base		DN of the base object
+ *	scope		the search scope - one of LDAP_SCOPE_BASE,
+ *			    LDAP_SCOPE_ONELEVEL, LDAP_SCOPE_SUBTREE
+ *	filter		a string containing the search filter
+ *			(e.g., "(|(cn=bob)(sn=bob))")
+ *	attrs		list of attribute types to return for matches
+ *	attrsonly	1 => attributes only 0 => attributes and values
+ *
+ * Example:
+ *	char	*attrs[] = { "mail", "title", 0 };
+ *	msgid = ldap_search( ld, "c=us@o=UM", LDAP_SCOPE_SUBTREE, "cn~=bob",
+ *	    attrs, attrsonly );
+ */
+int
+LDAP_CALL
+ldap_search(
+    LDAP 	*ld,
+    const char 	*base,
+    int 	scope,
+    const char 	*filter,
+    char 	**attrs,
+    int 	attrsonly
+)
+{
+	int		msgid;
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_search\n", 0, 0, 0 );
+
+	if ( ldap_search_ext( ld, base, scope, filter, attrs, attrsonly, NULL,
+	    NULL, NULL, -1, &msgid ) == LDAP_SUCCESS ) {
+		return( msgid );
+	} else {
+		return( -1 );	/* error is in ld handle */
+	}
+}
+
+
+/*
+ * LDAPv3 extended search.
+ * Returns an LDAP error code.
+ */
+int
+LDAP_CALL
+ldap_search_ext(
+    LDAP 		*ld,
+    const char 		*base,
+    int 		scope,
+    const char 		*filter,
+    char 		**attrs,
+    int 		attrsonly,
+    LDAPControl		**serverctrls,
+    LDAPControl		**clientctrls,
+    struct timeval	*timeoutp,	/* NULL means use ld->ld_timelimit */
+    int			sizelimit,
+    int			*msgidp
+)
+{
+	/*
+	 * It is an error to pass in a zero'd timeval.
+	 */
+	if ( timeoutp != NULL && timeoutp->tv_sec == 0 &&
+	    timeoutp->tv_usec == 0 ) {
+		if ( ld != NULL ) {
+			LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+		}
+                return( LDAP_PARAM_ERROR );
+        }
+
+	return( nsldapi_search( ld, base, scope, filter, attrs, attrsonly,
+	    serverctrls, clientctrls,
+	    nsldapi_timeval2ldaplimit( timeoutp, -1 ), sizelimit, msgidp ));
+}
+
+
+/*
+ * Like ldap_search_ext() except an integer timelimit is passed instead of
+ * using the overloaded struct timeval *timeoutp.
+ */
+static int
+nsldapi_search(
+    LDAP 		*ld,
+    const char 		*base,
+    int 		scope,
+    const char 		*filter,
+    char 		**attrs,
+    int 		attrsonly,
+    LDAPControl		**serverctrls,
+    LDAPControl		**clientctrls,
+    int			timelimit,	/* -1 means use ld->ld_timelimit */
+    int			sizelimit,	/* -1 means use ld->ld_sizelimit */
+    int			*msgidp
+)
+{
+	BerElement	*ber;
+	int		rc, rc_key;
+	unsigned long	key;	/* XXXmcs: memcache */
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_search_ext\n", 0, 0, 0 );
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( LDAP_PARAM_ERROR );
+	}
+
+	if ( base == NULL ) {
+	    base = "";
+	}
+
+	if ( filter == NULL ) {
+	    filter = "(objectclass=*)";
+	}
+
+	if ( msgidp == NULL || ( scope != LDAP_SCOPE_BASE
+	    && scope != LDAP_SCOPE_ONELEVEL && scope != LDAP_SCOPE_SUBTREE )
+		|| ( sizelimit < -1 )) {
+		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+                return( LDAP_PARAM_ERROR );
+        }
+	LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK );
+	*msgidp = ++ld->ld_msgid;
+	LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK );
+
+	/*
+	 * XXXmcs: should use cache function pointers to hook in memcache
+	 */
+	if ( ld->ld_memcache == NULL ) {
+		rc_key = LDAP_NOT_SUPPORTED;
+	} else if (( rc_key = ldap_memcache_createkey( ld, base, scope, filter,
+	    attrs, attrsonly, serverctrls, clientctrls, &key)) == LDAP_SUCCESS
+	    && ldap_memcache_result( ld, *msgidp, key ) == LDAP_SUCCESS ) {
+		return LDAP_SUCCESS;
+	}
+
+	/* check the cache */
+	if ( ld->ld_cache_on && ld->ld_cache_search != NULL ) {
+		LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK );
+		if ( (rc = (ld->ld_cache_search)( ld, *msgidp, LDAP_REQ_SEARCH,
+		    base, scope, filter, attrs, attrsonly )) != 0 ) {
+			*msgidp = rc;
+			LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+			return( LDAP_SUCCESS );
+		}
+		LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+	}
+
+	/* caching off or did not find it in the cache - check the net */
+	if (( rc = nsldapi_build_search_req( ld, base, scope, filter, attrs,
+	    attrsonly, serverctrls, clientctrls, timelimit, sizelimit,
+	    *msgidp, &ber )) != LDAP_SUCCESS ) {
+		return( rc );
+	}
+
+	/* send the message */
+	rc = nsldapi_send_initial_request( ld, *msgidp, LDAP_REQ_SEARCH,
+		(char *) base, ber );
+
+	/*
+	 * XXXmcs: should use cache function pointers to hook in memcache
+	 */
+	if ( (rc_key == LDAP_SUCCESS) && (rc >= 0) ) {
+		ldap_memcache_new( ld, rc, key, base );
+	}
+
+	*msgidp = rc;
+	return( rc < 0 ? LDAP_GET_LDERRNO( ld, NULL, NULL ) : LDAP_SUCCESS );
+}
+
+
+/*
+ * Convert a non-NULL timeoutp to a value in seconds that is appropriate to
+ * send in an LDAP search request.  If timeoutp is NULL, return defaultvalue.
+ */
+static int
+nsldapi_timeval2ldaplimit( struct timeval *timeoutp, int defaultvalue )
+{
+	int		timelimit;
+
+	if ( NULL == timeoutp ) {
+		timelimit = defaultvalue;
+	} else if ( timeoutp->tv_sec > 0 ) {
+		timelimit = timeoutp->tv_sec;
+	} else if ( timeoutp->tv_usec > 0 ) {
+		timelimit = 1;	/* minimum we can express in LDAP */
+	} else {
+		/*
+		 * both tv_sec and tv_usec are less than one (zero?) so
+		 * to maintain compatiblity with our "zero means no limit"
+		 * convention we pass no limit to the server.
+		 */
+		timelimit = 0;	/* no limit */
+	}
+
+	return( timelimit );
+}
+
+
+/* returns an LDAP error code and also sets it in ld */
+int
+nsldapi_build_search_req(
+    LDAP		*ld, 
+    const char		*base, 
+    int			scope, 
+    const char		*filter,
+    char		**attrs, 
+    int			attrsonly,
+    LDAPControl		**serverctrls,
+    LDAPControl		**clientctrls,	/* not used for anything yet */
+    int			timelimit,	/* if -1, ld->ld_timelimit is used */
+    int			sizelimit,	/* if -1, ld->ld_sizelimit is used */
+    int			msgid,
+    BerElement		**berp
+)
+{
+	BerElement	*ber;
+	int		err;
+	char		*fdup;
+
+	/*
+	 * Create the search request.  It looks like this:
+	 *	SearchRequest := [APPLICATION 3] SEQUENCE {
+	 *		baseObject	DistinguishedName,
+	 *		scope		ENUMERATED {
+	 *			baseObject	(0),
+	 *			singleLevel	(1),
+	 *			wholeSubtree	(2)
+	 *		},
+	 *		derefAliases	ENUMERATED {
+	 *			neverDerefaliases	(0),
+	 *			derefInSearching	(1),
+	 *			derefFindingBaseObj	(2),
+	 *			alwaysDerefAliases	(3)
+	 *		},
+	 *		sizelimit	INTEGER (0 .. 65535),
+	 *		timelimit	INTEGER (0 .. 65535),
+	 *		attrsOnly	BOOLEAN,
+	 *		filter		Filter,
+	 *		attributes	SEQUENCE OF AttributeType
+	 *	}
+	 * wrapped in an ldap message.
+	 */
+
+	/* create a message to send */
+	if (( err = nsldapi_alloc_ber_with_options( ld, &ber ))
+	    != LDAP_SUCCESS ) {
+		return( err );
+	}
+
+	if ( base == NULL ) {
+	    base = "";
+	}
+
+	if ( sizelimit == -1 ) {
+	    sizelimit = ld->ld_sizelimit;
+	}
+
+	if ( timelimit == -1 ) {
+	    timelimit = ld->ld_timelimit;
+	}
+
+#ifdef CLDAP
+	if ( ld->ld_sbp->sb_naddr > 0 ) {
+	    err = ber_printf( ber, "{ist{seeiib", msgid,
+		ld->ld_cldapdn, LDAP_REQ_SEARCH, base, scope, ld->ld_deref,
+		sizelimit, timelimit, attrsonly );
+	} else {
+#endif /* CLDAP */
+		err = ber_printf( ber, "{it{seeiib", msgid,
+		    LDAP_REQ_SEARCH, base, scope, ld->ld_deref,
+		    sizelimit, timelimit, attrsonly );
+#ifdef CLDAP
+	}
+#endif /* CLDAP */
+
+	if ( err == -1 ) {
+		LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
+		ber_free( ber, 1 );
+		return( LDAP_ENCODING_ERROR );
+	}
+
+	fdup = nsldapi_strdup( filter );
+	err = put_filter( ber, fdup );
+	NSLDAPI_FREE( fdup );
+
+	if ( err == -1 ) {
+		LDAP_SET_LDERRNO( ld, LDAP_FILTER_ERROR, NULL, NULL );
+		ber_free( ber, 1 );
+		return( LDAP_FILTER_ERROR );
+	}
+
+	if ( ber_printf( ber, "{v}}", attrs ) == -1 ) {
+		LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
+		ber_free( ber, 1 );
+		return( LDAP_ENCODING_ERROR );
+	}
+
+	if ( (err = nsldapi_put_controls( ld, serverctrls, 1, ber ))
+	    != LDAP_SUCCESS ) {
+		ber_free( ber, 1 );
+		return( err );
+	}
+
+	*berp = ber;
+	return( LDAP_SUCCESS );
+}
+
+static char *
+find_right_paren( char *s )
+{
+	int	balance, escape;
+
+	balance = 1;
+	escape = 0;
+	while ( *s && balance ) {
+		if ( escape == 0 ) {
+			if ( *s == '(' )
+				balance++;
+			else if ( *s == ')' )
+				balance--;
+		}
+		if ( *s == '\\' && ! escape )
+			escape = 1;
+		else
+			escape = 0;
+		if ( balance )
+			s++;
+	}
+
+	return( *s ? s : NULL );
+}
+
+static char *
+put_complex_filter(
+    BerElement		*ber, 
+    char		*str, 
+    unsigned long	tag, 
+    int			not 
+)
+{
+	char	*next;
+
+	/*
+	 * We have (x(filter)...) with str sitting on
+	 * the x.  We have to find the paren matching
+	 * the one before the x and put the intervening
+	 * filters by calling put_filter_list().
+	 */
+
+	/* put explicit tag */
+	if ( ber_printf( ber, "t{", tag ) == -1 )
+		return( NULL );
+
+	str++;
+	if ( (next = find_right_paren( str )) == NULL )
+		return( NULL );
+
+	*next = '\0';
+	if ( put_filter_list( ber, str ) == -1 )
+		return( NULL );
+	*next++ = ')';
+
+	/* flush explicit tagged thang */
+	if ( ber_printf( ber, "}" ) == -1 )
+		return( NULL );
+
+	return( next );
+}
+
+static int
+put_filter( BerElement *ber, char *str )
+{
+	char	*next;
+	int	parens, balance, escape;
+
+	/*
+	 * A Filter looks like this:
+	 *      Filter ::= CHOICE {
+	 *              and             [0]     SET OF Filter,
+	 *              or              [1]     SET OF Filter,
+	 *              not             [2]     Filter,
+	 *              equalityMatch   [3]     AttributeValueAssertion,
+	 *              substrings      [4]     SubstringFilter,
+	 *              greaterOrEqual  [5]     AttributeValueAssertion,
+	 *              lessOrEqual     [6]     AttributeValueAssertion,
+	 *              present         [7]     AttributeType,,
+	 *              approxMatch     [8]     AttributeValueAssertion
+	 *      }
+	 *
+	 *      SubstringFilter ::= SEQUENCE {
+	 *              type               AttributeType,
+	 *              SEQUENCE OF CHOICE {
+	 *                      initial          [0] IA5String,
+	 *                      any              [1] IA5String,
+	 *                      final            [2] IA5String
+	 *              }
+	 *      }
+	 * Note: tags in a choice are always explicit
+	 */
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "put_filter \"%s\"\n", str, 0, 0 );
+
+	parens = 0;
+	while ( *str ) {
+		switch ( *str ) {
+		case '(':
+			str++;
+			parens++;
+			switch ( *str ) {
+			case '&':
+				LDAPDebug( LDAP_DEBUG_TRACE, "put_filter: AND\n",
+				    0, 0, 0 );
+
+				if ( (str = put_complex_filter( ber, str,
+				    LDAP_FILTER_AND, 0 )) == NULL )
+					return( -1 );
+
+				parens--;
+				break;
+
+			case '|':
+				LDAPDebug( LDAP_DEBUG_TRACE, "put_filter: OR\n",
+				    0, 0, 0 );
+
+				if ( (str = put_complex_filter( ber, str,
+				    LDAP_FILTER_OR, 0 )) == NULL )
+					return( -1 );
+
+				parens--;
+				break;
+
+			case '!':
+				LDAPDebug( LDAP_DEBUG_TRACE, "put_filter: NOT\n",
+				    0, 0, 0 );
+
+				if ( (str = put_complex_filter( ber, str,
+				    LDAP_FILTER_NOT, 1 )) == NULL )
+					return( -1 );
+
+				parens--;
+				break;
+
+			default:
+				LDAPDebug( LDAP_DEBUG_TRACE,
+				    "put_filter: simple\n", 0, 0, 0 );
+
+				balance = 1;
+				escape = 0;
+				next = str;
+				while ( *next && balance ) {
+					if ( escape == 0 ) {
+						if ( *next == '(' )
+							balance++;
+						else if ( *next == ')' )
+							balance--;
+					}
+					if ( *next == '\\' && ! escape )
+						escape = 1;
+					else
+						escape = 0;
+					if ( balance )
+						next++;
+				}
+				if ( balance != 0 )
+					return( -1 );
+
+				*next = '\0';
+				if ( put_simple_filter( ber, str ) == -1 ) {
+					return( -1 );
+				}
+				*next++ = ')';
+				str = next;
+				parens--;
+				break;
+			}
+			break;
+
+		case ')':
+			LDAPDebug( LDAP_DEBUG_TRACE, "put_filter: end\n", 0, 0,
+			    0 );
+			if ( ber_printf( ber, "]" ) == -1 )
+				return( -1 );
+			str++;
+			parens--;
+			break;
+
+		case ' ':
+			str++;
+			break;
+
+		default:	/* assume it's a simple type=value filter */
+			LDAPDebug( LDAP_DEBUG_TRACE, "put_filter: default\n", 0, 0,
+			    0 );
+			next = strchr( str, '\0' );
+			if ( put_simple_filter( ber, str ) == -1 ) {
+				return( -1 );
+			}
+			str = next;
+			break;
+		}
+	}
+
+	return( parens ? -1 : 0 );
+}
+
+
+/*
+ * Put a list of filters like this "(filter1)(filter2)..."
+ */
+
+static int
+put_filter_list( BerElement *ber, char *str )
+{
+	char	*next;
+	char	save;
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "put_filter_list \"%s\"\n", str, 0, 0 );
+
+	while ( *str ) {
+		while ( *str && isspace( *str ) )
+			str++;
+		if ( *str == '\0' )
+			break;
+
+		if ( (next = find_right_paren( str + 1 )) == NULL )
+			return( -1 );
+		save = *++next;
+
+		/* now we have "(filter)" with str pointing to it */
+		*next = '\0';
+		if ( put_filter( ber, str ) == -1 )
+			return( -1 );
+		*next = save;
+
+		str = next;
+	}
+
+	return( 0 );
+}
+
+
+/*
+ * is_valid_attr - returns 1 if a is a syntactically valid left-hand side
+ * of a filter expression, 0 otherwise.  A valid string may contain only
+ * letters, numbers, hyphens, semi-colons, colons and periods. examples:
+ *	cn
+ *	cn;lang-fr
+ *	1.2.3.4;binary;dynamic
+ *	mail;dynamic
+ *	cn:dn:1.2.3.4
+ *
+ * For compatibility with older servers, we also allow underscores in
+ * attribute types, even through they are not allowed by the LDAPv3 RFCs.
+ */
+static int
+is_valid_attr( char *a )
+{
+	for ( ; *a; a++ ) {
+	    if ( !isascii( *a ) ) {
+		return( 0 );
+	    } else if ( !isalnum( *a ) ) {
+		switch ( *a ) {
+		  case '-':
+		  case '.':
+		  case ';':
+		  case ':':
+		  case '_':
+		    break; /* valid */
+		  default:
+		    return( 0 );
+		}
+	    }
+	}
+
+	return( 1 );
+}
+
+static char *
+find_star( char *s )
+{
+    for ( ; *s; ++s ) {
+	switch ( *s ) {
+	  case '*': return s;
+	  case '\\':
+	    ++s;
+	    if ( hexchar2int(s[0]) >= 0 && hexchar2int(s[1]) >= 0 ) ++s;
+	  default: break;
+	}
+    }
+    return NULL;
+}
+
+static int
+put_simple_filter( BerElement *ber, char *str )
+{
+	char		*s, *s2, *s3, filterop;
+	char		*value;
+	unsigned long	ftype;
+	int		rc, len;
+	char		*oid;	/* for v3 extended filter */
+	int		dnattr;	/* for v3 extended filter */
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "put_simple_filter \"%s\"\n", str, 0, 0 );
+
+	rc = -1;	/* pessimistic */
+
+	if (( str = nsldapi_strdup( str )) == NULL ) {
+		return( rc );
+	}
+
+	if ( (s = strchr( str, '=' )) == NULL ) {
+		goto free_and_return;
+	}
+	value = s + 1;
+	*s-- = '\0';
+	filterop = *s;
+	if ( filterop == '<' || filterop == '>' || filterop == '~' ||
+	    filterop == ':' ) {
+		*s = '\0';
+	}
+
+	if ( ! is_valid_attr( str ) ) {
+		goto free_and_return;
+	}
+
+	switch ( filterop ) {
+	case '<':
+		ftype = LDAP_FILTER_LE;
+		break;
+	case '>':
+		ftype = LDAP_FILTER_GE;
+		break;
+	case '~':
+		ftype = LDAP_FILTER_APPROX;
+		break;
+	case ':':	/* extended filter - v3 only */
+		/*
+		 * extended filter looks like this:
+		 *
+		 *	[type][':dn'][':'oid]':='value
+		 *
+		 * where one of type or :oid is required.
+		 *
+		 */
+		ftype = LDAP_FILTER_EXTENDED;
+		s2 = s3 = NULL;
+		if ( (s2 = strrchr( str, ':' )) == NULL ) {
+			goto free_and_return;
+		}
+		if ( strcasecmp( s2, ":dn" ) == 0 ) {
+			oid = NULL;
+			dnattr = 1;
+			*s2 = '\0';
+		} else {
+			oid = s2 + 1;
+			dnattr = 0;
+			*s2 = '\0';
+			if ( (s3 = strrchr( str, ':' )) != NULL ) {
+				if ( strcasecmp( s3, ":dn" ) == 0 ) {
+					dnattr = 1;
+				} else {
+					goto free_and_return;
+				}
+				*s3 = '\0';
+			}
+		}
+		if ( (rc = ber_printf( ber, "t{", ftype )) == -1 ) {
+			goto free_and_return;
+		}
+		if ( oid != NULL ) {
+			if ( (rc = ber_printf( ber, "ts", LDAP_TAG_MRA_OID,
+			    oid )) == -1 ) {
+				goto free_and_return;
+			}
+		}
+		if ( *str != '\0' ) {
+			if ( (rc = ber_printf( ber, "ts",
+			    LDAP_TAG_MRA_TYPE, str )) == -1 ) {
+				goto free_and_return;
+			}
+		}
+		if (( len = unescape_filterval( value )) < 0 ||
+		    ( rc = ber_printf( ber, "totb}", LDAP_TAG_MRA_VALUE,
+		    value, len, LDAP_TAG_MRA_DNATTRS, dnattr )) == -1 ) {
+			goto free_and_return;
+		}
+		rc = 0;
+		goto free_and_return;
+		break;
+	default:
+		if ( find_star( value ) == NULL ) {
+			ftype = LDAP_FILTER_EQUALITY;
+		} else if ( strcmp( value, "*" ) == 0 ) {
+			ftype = LDAP_FILTER_PRESENT;
+		} else {
+			rc = put_substring_filter( ber, str, value );
+			goto free_and_return;
+		}
+		break;
+	}
+
+	if ( ftype == LDAP_FILTER_PRESENT ) {
+		rc = ber_printf( ber, "ts", ftype, str );
+	} else if (( len = unescape_filterval( value )) >= 0 ) {
+		rc = ber_printf( ber, "t{so}", ftype, str, value, len );
+	}
+	if ( rc != -1 ) {
+		rc = 0;
+	}
+
+free_and_return:
+	NSLDAPI_FREE( str );
+	return( rc );
+}
+
+
+/*
+ * Undo in place both LDAPv2 (RFC-1960) and LDAPv3 (hexadecimal) escape
+ * sequences within the null-terminated string 'val'.  The resulting value
+ * may contain null characters.
+ *
+ * If 'val' contains invalid escape sequences we return -1.
+ * Otherwise the length of the unescaped value is returned.
+ */
+static int
+unescape_filterval( char *val )
+{
+	int	escape, firstdigit, ival; 
+	char	*s, *d;
+
+	escape = firstdigit = 0;
+	for ( s = d = val; *s; s++ ) {
+		if ( escape ) {
+			/*
+			 * first try LDAPv3 escape (hexadecimal) sequence
+			 */
+			if (( ival = hexchar2int( *s )) < 0 ) {
+				if ( firstdigit ) {
+					/*
+					 * LDAPv2 (RFC1960) escape sequence
+					 */
+					*d++ = *s;
+					escape = 0;
+				} else {
+					return(-1);
+				}
+			}
+			if ( firstdigit ) {
+			    *d = ( ival<<4 );
+			    firstdigit = 0;
+			} else {
+			    *d++ |= ival;
+			    escape = 0;
+			}
+
+		} else if ( *s != '\\' ) {
+			*d++ = *s;
+			escape = 0;
+
+		} else {
+			escape = 1;
+			firstdigit = 1;
+		}
+	}
+
+	return( d - val );
+}
+
+
+/*
+ * convert character 'c' that represents a hexadecimal digit to an integer.
+ * if 'c' is not a hexidecimal digit [0-9A-Fa-f], -1 is returned.
+ * otherwise the converted value is returned.
+ */
+static int
+hexchar2int( char c )
+{
+    if ( c >= '0' && c <= '9' ) {
+	return( c - '0' );
+    }
+    if ( c >= 'A' && c <= 'F' ) {
+	return( c - 'A' + 10 );
+    }
+    if ( c >= 'a' && c <= 'f' ) {
+	return( c - 'a' + 10 );
+    }
+    return( -1 );
+}
+
+static int
+put_substring_filter( BerElement *ber, char *type, char *val )
+{
+	char		*nextstar, gotstar = 0;
+	unsigned long	ftype;
+	int		len;
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "put_substring_filter \"%s=%s\"\n", type,
+	    val, 0 );
+
+	if ( ber_printf( ber, "t{s{", LDAP_FILTER_SUBSTRINGS, type ) == -1 ) {
+		return( -1 );
+	}
+
+	for ( ; val != NULL; val = nextstar ) {
+		if ( (nextstar = find_star( val )) != NULL ) {
+			*nextstar++ = '\0';
+		}
+
+		if ( gotstar == 0 ) {
+			ftype = LDAP_SUBSTRING_INITIAL;
+		} else if ( nextstar == NULL ) {
+			ftype = LDAP_SUBSTRING_FINAL;
+		} else {
+			ftype = LDAP_SUBSTRING_ANY;
+		}
+		if ( *val != '\0' ) {
+			if (( len = unescape_filterval( val )) < 0 ||
+			    ber_printf( ber, "to", ftype, val, len ) == -1 ) {
+				return( -1 );
+			}
+		}
+
+		gotstar = 1;
+	}
+
+	if ( ber_printf( ber, "}}" ) == -1 ) {
+		return( -1 );
+	}
+
+	return( 0 );
+}
+
+int
+LDAP_CALL
+ldap_search_st(
+    LDAP		*ld, 
+    const char 		*base, 
+    int 		scope, 
+    const char 		*filter, 
+    char 		**attrs,
+    int 		attrsonly, 
+    struct timeval	*timeout, 
+    LDAPMessage 	**res
+)
+{
+	return( nsldapi_search_s( ld, base, scope, filter, attrs, attrsonly,
+	    NULL, NULL, timeout, -1, -1, res ));
+}
+
+int
+LDAP_CALL
+ldap_search_s(
+    LDAP	*ld, 
+    const char 	*base, 
+    int 	scope, 
+    const char 	*filter, 
+    char 	**attrs,
+    int		attrsonly, 
+    LDAPMessage	**res
+)
+{
+	return( nsldapi_search_s( ld, base, scope, filter, attrs, attrsonly,
+	    NULL, NULL, NULL, -1, -1, res ));
+}
+
+int LDAP_CALL
+ldap_search_ext_s(
+    LDAP		*ld, 
+    const char 		*base, 
+    int 		scope, 
+    const char 		*filter, 
+    char 		**attrs,
+    int			attrsonly, 
+    LDAPControl		**serverctrls,
+    LDAPControl		**clientctrls,
+    struct timeval	*timeoutp,
+    int			sizelimit,
+    LDAPMessage		**res
+)
+{
+	return( nsldapi_search_s( ld, base, scope, filter, attrs, attrsonly,
+	    serverctrls, clientctrls, timeoutp,
+	    nsldapi_timeval2ldaplimit( timeoutp, -1 ), sizelimit, res ));
+}
+
+
+static int 
+nsldapi_search_s(
+    LDAP		*ld, 
+    const char 		*base, 
+    int 		scope, 
+    const char 		*filter, 
+    char 		**attrs,
+    int			attrsonly, 
+    LDAPControl		**serverctrls,
+    LDAPControl		**clientctrls,
+    struct timeval	*localtimeoutp,
+    int			timelimit,	/* -1 means use ld->ld_timelimit */
+    int			sizelimit,	/* -1 means use ld->ld_sizelimit */
+    LDAPMessage		**res
+)
+{
+	int	err, msgid;
+
+	/*
+	 * It is an error to pass in a zero'd timeval.
+	 */
+	if ( localtimeoutp != NULL && localtimeoutp->tv_sec == 0 &&
+	    localtimeoutp->tv_usec == 0 ) {
+		if ( ld != NULL ) {
+			LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+		}
+		if ( res != NULL ) {
+			*res = NULL;
+		}
+                return( LDAP_PARAM_ERROR );
+        }
+
+	if (( err = nsldapi_search( ld, base, scope, filter, attrs, attrsonly,
+	    serverctrls, clientctrls, timelimit, sizelimit, &msgid ))
+	    != LDAP_SUCCESS ) {
+		if ( res != NULL ) {
+			*res = NULL;
+		}
+		return( err );
+	}
+
+	if ( ldap_result( ld, msgid, 1, localtimeoutp, res ) == -1 ) {
+		/*
+		 * Error.  ldap_result() sets *res to NULL for us.
+		 */
+		return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+	}
+
+	if ( LDAP_GET_LDERRNO( ld, NULL, NULL ) == LDAP_TIMEOUT ) {
+		(void) ldap_abandon( ld, msgid );
+		err = LDAP_TIMEOUT;
+		LDAP_SET_LDERRNO( ld, err, NULL, NULL );
+		if ( res != NULL ) {
+			*res = NULL;
+		}
+		return( err );
+	}
+
+	return( ldap_result2error( ld, *res, 0 ) );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/setoption.c
@@ -0,0 +1,411 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ * setoption.c - ldap_set_option implementation 
+ */
+
+#include "ldap-int.h"
+
+#define LDAP_SETCLR_BITOPT( ld, bit, optdata ) \
+	if ( optdata != NULL ) {		\
+		(ld)->ld_options |= bit;	\
+	} else {				\
+		(ld)->ld_options &= ~bit;	\
+	}
+
+
+int
+LDAP_CALL
+ldap_set_option( LDAP *ld, int option, const void *optdata )
+{
+	int		rc, i;
+	char		*matched, *errstr;
+
+	/*
+         * if ld is NULL, arrange to modify our default settings
+         */
+        if ( ld == NULL ) {
+		if ( !nsldapi_initialized ) {
+			nsldapi_initialize_defaults();
+		}
+		ld = &nsldapi_ld_defaults;
+	}
+
+	/*
+	 * process global options (not associated with an LDAP session handle)
+	 */
+	if ( option == LDAP_OPT_MEMALLOC_FN_PTRS ) {
+		struct lber_memalloc_fns	memalloc_fns;
+
+		/* set libldap ones via a struct copy */
+		nsldapi_memalloc_fns = *((struct ldap_memalloc_fns *)optdata);
+
+		/* also set liblber memory allocation callbacks */
+		memalloc_fns.lbermem_malloc =
+		    nsldapi_memalloc_fns.ldapmem_malloc;
+		memalloc_fns.lbermem_calloc =
+		    nsldapi_memalloc_fns.ldapmem_calloc;
+		memalloc_fns.lbermem_realloc =
+		    nsldapi_memalloc_fns.ldapmem_realloc;
+		memalloc_fns.lbermem_free =
+		    nsldapi_memalloc_fns.ldapmem_free;
+		if ( ber_set_option( NULL, LBER_OPT_MEMALLOC_FN_PTRS,
+		    &memalloc_fns ) != 0 ) {
+			return( -1 );
+		}
+
+		return( 0 );
+	}
+	/* 
+     * LDAP_OPT_DEBUG_LEVEL is global 
+     */
+    if (LDAP_OPT_DEBUG_LEVEL == option) 
+    {
+#ifdef LDAP_DEBUG	  
+        ldap_debug = *((int *) optdata);
+#endif
+        return 0;
+    }
+
+	/*
+	 * process options that are associated with an LDAP session handle
+	 */
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( -1 );	/* punt */
+	}
+
+	rc = 0;
+	if ( ld != &nsldapi_ld_defaults
+		&& option != LDAP_OPT_EXTRA_THREAD_FN_PTRS
+		&& option != LDAP_OPT_THREAD_FN_PTRS ) {
+	    LDAP_MUTEX_LOCK( ld, LDAP_OPTION_LOCK );
+	}
+	switch( option ) {
+	/* options that can be turned on and off */
+#ifdef LDAP_DNS
+	case LDAP_OPT_DNS:
+		LDAP_SETCLR_BITOPT( ld, LDAP_BITOPT_DNS, optdata );
+		break;
+#endif
+
+	case LDAP_OPT_REFERRALS:
+		LDAP_SETCLR_BITOPT( ld, LDAP_BITOPT_REFERRALS, optdata );
+		break;
+
+	case LDAP_OPT_SSL:
+		LDAP_SETCLR_BITOPT( ld, LDAP_BITOPT_SSL, optdata );
+		break;
+
+	case LDAP_OPT_RESTART:
+		LDAP_SETCLR_BITOPT( ld, LDAP_BITOPT_RESTART, optdata );
+		break;
+
+	case LDAP_OPT_RECONNECT:
+		LDAP_SETCLR_BITOPT( ld, LDAP_BITOPT_RECONNECT, optdata );
+		break;
+
+	case LDAP_OPT_NOREBIND:
+		LDAP_SETCLR_BITOPT( ld, LDAP_BITOPT_NOREBIND, optdata );
+		break;
+
+#ifdef LDAP_ASYNC_IO
+	case LDAP_OPT_ASYNC_CONNECT:
+ 		LDAP_SETCLR_BITOPT(ld, LDAP_BITOPT_ASYNC, optdata );
+	 	break;
+#endif /* LDAP_ASYNC_IO */
+
+	/* fields in the LDAP structure */
+	case LDAP_OPT_DEREF:
+		ld->ld_deref = *((int *) optdata);
+		break;
+	case LDAP_OPT_SIZELIMIT:
+		ld->ld_sizelimit = *((int *) optdata);
+                break;  
+	case LDAP_OPT_TIMELIMIT:
+		ld->ld_timelimit = *((int *) optdata);
+                break;
+	case LDAP_OPT_REFERRAL_HOP_LIMIT:
+		ld->ld_refhoplimit = *((int *) optdata);
+		break;
+	case LDAP_OPT_PROTOCOL_VERSION:
+		ld->ld_version = *((int *) optdata);
+		if ( ld->ld_defconn != NULL ) {	/* also set in default conn. */
+			ld->ld_defconn->lconn_version = ld->ld_version;
+		}
+		break;
+	case LDAP_OPT_SERVER_CONTROLS:
+		/* nsldapi_dup_controls returns -1 and sets lderrno on error */
+		rc = nsldapi_dup_controls( ld, &ld->ld_servercontrols,
+		    (LDAPControl **)optdata );
+		break;
+	case LDAP_OPT_CLIENT_CONTROLS:
+		/* nsldapi_dup_controls returns -1 and sets lderrno on error */
+		rc = nsldapi_dup_controls( ld, &ld->ld_clientcontrols,
+		    (LDAPControl **)optdata );
+		break;
+
+	/* rebind proc */
+	case LDAP_OPT_REBIND_FN:
+		ld->ld_rebind_fn = (LDAP_REBINDPROC_CALLBACK *) optdata;
+		break;
+	case LDAP_OPT_REBIND_ARG:
+		ld->ld_rebind_arg = (void *) optdata;
+		break;
+
+	/* i/o function pointers */
+	case LDAP_OPT_IO_FN_PTRS:
+		if (( rc = nsldapi_install_compat_io_fns( ld,
+		    (struct ldap_io_fns *)optdata )) != LDAP_SUCCESS ) {
+			LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+			rc = -1;
+		}
+		break;
+
+	/* extended i/o function pointers */
+	case LDAP_X_OPT_EXTIO_FN_PTRS:
+	  /* denotes use of old iofns struct (no writev) */
+	  if (((struct ldap_x_ext_io_fns_rev0 *) optdata)->lextiof_size == LDAP_X_EXTIO_FNS_SIZE_REV0) {
+	    ld->ld_extio_size = LDAP_X_EXTIO_FNS_SIZE;
+	    ld->ld_extclose_fn = ((struct ldap_x_ext_io_fns_rev0 *) optdata)->lextiof_close;
+	    ld->ld_extconnect_fn = ((struct ldap_x_ext_io_fns_rev0 *) optdata)->lextiof_connect;
+	    ld->ld_extread_fn = ((struct ldap_x_ext_io_fns_rev0 *) optdata)->lextiof_read;
+	    ld->ld_extwrite_fn = ((struct ldap_x_ext_io_fns_rev0 *) optdata)->lextiof_write;
+	    ld->ld_extpoll_fn = ((struct ldap_x_ext_io_fns_rev0 *) optdata)->lextiof_poll;
+	    ld->ld_extnewhandle_fn = ((struct ldap_x_ext_io_fns_rev0 *) optdata)->lextiof_newhandle;
+	    ld->ld_extdisposehandle_fn = ((struct ldap_x_ext_io_fns_rev0 *) optdata)->lextiof_disposehandle;
+	    ld->ld_ext_session_arg = ((struct ldap_x_ext_io_fns_rev0 *) optdata)->lextiof_session_arg;
+	    ld->ld_extwritev_fn = NULL;
+	    if ( ber_sockbuf_set_option( ld->ld_sbp, LBER_SOCKBUF_OPT_EXT_IO_FNS,
+					 &(ld->ld_ext_io_fns) ) != 0 ) {
+	      LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL, NULL );
+	      rc = -1;
+	      break;
+	    }
+	  }
+	  else {
+	    /* struct copy */
+	    ld->ld_ext_io_fns = *((struct ldap_x_ext_io_fns *) optdata);
+	  }
+	  if (( rc = nsldapi_install_lber_extiofns( ld, ld->ld_sbp ))
+	      != LDAP_SUCCESS ) {
+	    LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+	    rc = -1;
+	  }
+	  break;
+
+	 /* set Socket Arg in extended socket i/o functions*/
+	case LDAP_X_OPT_SOCKETARG:
+	  if ( ber_sockbuf_set_option( ld->ld_sbp,
+	    LBER_SOCKBUF_OPT_SOCK_ARG, (void *)optdata ) != 0 ) {
+		LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL, NULL );
+		rc = -1;
+	  }
+		
+	  break;
+	  
+	/* thread function pointers */
+	case LDAP_OPT_THREAD_FN_PTRS:
+		/*
+		 * It is only safe to set the thread function pointers
+		 * when one thread is using the LDAP session handle.
+		 */
+		/* free existing mutexes (some are allocated by ldap_init()) */
+		nsldapi_mutex_free_all( ld );
+
+		/* struct copy */
+		ld->ld_thread = *((struct ldap_thread_fns *) optdata);
+
+		/* allocate new mutexes */
+		nsldapi_mutex_alloc_all( ld );
+
+		/* LDAP_OPTION_LOCK was never locked... so just return */
+		return (rc);
+
+	/* extra thread function pointers */
+	case LDAP_OPT_EXTRA_THREAD_FN_PTRS:
+	/* The extra thread funcs will only pick up the threadid */
+	    ld->ld_thread2  = *((struct ldap_extra_thread_fns *) optdata);
+	    
+	/* Reset the rest of the structure preserving the threadid fn */
+	    ld->ld_mutex_trylock_fn =  (LDAP_TF_MUTEX_TRYLOCK_CALLBACK *)NULL;
+	    ld->ld_sema_alloc_fn = (LDAP_TF_SEMA_ALLOC_CALLBACK *) NULL;
+	    ld->ld_sema_free_fn = (LDAP_TF_SEMA_FREE_CALLBACK *) NULL;
+	    ld->ld_sema_wait_fn = (LDAP_TF_SEMA_WAIT_CALLBACK *) NULL;
+	    ld->ld_sema_post_fn = (LDAP_TF_SEMA_POST_CALLBACK *) NULL;
+
+	/* We assume that only one thread is active when replacing */
+	/* the threadid function.  We will now proceed and reset all */
+	/* of the threadid/refcounts */
+	    for( i=0; i<LDAP_MAX_LOCK; i++ ) {
+                ld->ld_mutex_threadid[i] = (void *) -1;
+                ld->ld_mutex_refcnt[i] = 0;
+            }
+
+	/* LDAP_OPTION_LOCK was never locked... so just return */
+	    return (rc);
+
+	/* DNS function pointers */
+	case LDAP_OPT_DNS_FN_PTRS:
+		/* struct copy */
+		ld->ld_dnsfn = *((struct ldap_dns_fns *) optdata);
+		break;
+
+	/* cache function pointers */
+	case LDAP_OPT_CACHE_FN_PTRS:
+		/* struct copy */
+		ld->ld_cache = *((struct ldap_cache_fns *) optdata);
+		break;
+	case LDAP_OPT_CACHE_STRATEGY:
+		ld->ld_cache_strategy = *((int *) optdata);
+		break;
+	case LDAP_OPT_CACHE_ENABLE:
+		ld->ld_cache_on = *((int *) optdata);
+		break;
+
+	case LDAP_OPT_ERROR_NUMBER:
+		LDAP_GET_LDERRNO( ld, &matched, &errstr );
+		matched = nsldapi_strdup( matched );
+		errstr = nsldapi_strdup( errstr );
+		LDAP_SET_LDERRNO( ld, *((int *) optdata), matched, errstr );
+		break;
+
+	case LDAP_OPT_ERROR_STRING:
+		rc = LDAP_GET_LDERRNO( ld, &matched, NULL );
+		matched = nsldapi_strdup( matched );
+		LDAP_SET_LDERRNO( ld, rc, matched,
+		    nsldapi_strdup((char *) optdata));
+		rc = LDAP_SUCCESS;
+		break;
+
+	case LDAP_OPT_MATCHED_DN:
+		rc = LDAP_GET_LDERRNO( ld, NULL, &errstr );
+		errstr = nsldapi_strdup( errstr );
+		LDAP_SET_LDERRNO( ld, rc,
+		    nsldapi_strdup((char *) optdata), errstr );
+		rc = LDAP_SUCCESS;
+		break;
+
+	case LDAP_OPT_PREFERRED_LANGUAGE:
+		if ( NULL != ld->ld_preferred_language ) {
+			NSLDAPI_FREE(ld->ld_preferred_language);
+		}
+		ld->ld_preferred_language = nsldapi_strdup((char *) optdata);
+		break;
+
+	case LDAP_OPT_HOST_NAME:
+		if ( NULL != ld->ld_defhost ) {
+			NSLDAPI_FREE(ld->ld_defhost);
+		}
+		ld->ld_defhost = nsldapi_strdup((char *) optdata);
+		break;
+
+	case LDAP_X_OPT_CONNECT_TIMEOUT:
+		ld->ld_connect_timeout = *((int *) optdata);
+		break;
+
+#ifdef LDAP_SASLIO_HOOKS
+	/* SASL options */
+	case LDAP_OPT_X_SASL_MECH:
+		NSLDAPI_FREE(ld->ld_def_sasl_mech);
+		ld->ld_def_sasl_mech = nsldapi_strdup((char *) optdata);
+		break;
+	case LDAP_OPT_X_SASL_REALM:
+		NSLDAPI_FREE(ld->ld_def_sasl_realm);
+		ld->ld_def_sasl_realm = nsldapi_strdup((char *) optdata);
+		break;
+	case LDAP_OPT_X_SASL_AUTHCID:
+		NSLDAPI_FREE(ld->ld_def_sasl_authcid);
+		ld->ld_def_sasl_authcid = nsldapi_strdup((char *) optdata);
+		break;
+	case LDAP_OPT_X_SASL_AUTHZID:
+		NSLDAPI_FREE(ld->ld_def_sasl_authzid);
+		ld->ld_def_sasl_authzid = nsldapi_strdup((char *) optdata);
+		break;
+	case LDAP_OPT_X_SASL_SSF_EXTERNAL:
+		{
+			int sc;
+			sasl_ssf_t extprops;
+			sasl_conn_t *ctx;
+			if( ld->ld_defconn == NULL ) {
+				return -1;
+			}
+			ctx = (sasl_conn_t *)(ld->ld_defconn->lconn_sasl_ctx);
+			if ( ctx == NULL ) {
+				return -1;
+			}
+			memset(&extprops, 0L, sizeof(extprops));
+			extprops = * ((sasl_ssf_t *) optdata);
+			sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL,
+					(void *) &extprops );
+			if ( sc != SASL_OK ) {
+				return -1;
+			}
+		}
+		break;
+	case LDAP_OPT_X_SASL_SECPROPS:
+		{
+			int sc;
+			sc = nsldapi_sasl_secprops( (char *) optdata,
+					&ld->ld_sasl_secprops );
+			return sc == LDAP_SUCCESS ? 0 : -1;
+		}
+		break;
+	case LDAP_OPT_X_SASL_SSF_MIN:
+		ld->ld_sasl_secprops.min_ssf = *((sasl_ssf_t *) optdata);
+		break;
+	case LDAP_OPT_X_SASL_SSF_MAX:
+		ld->ld_sasl_secprops.max_ssf = *((sasl_ssf_t *) optdata);
+		break;
+	case LDAP_OPT_X_SASL_MAXBUFSIZE:
+		ld->ld_sasl_secprops.maxbufsize = *((sasl_ssf_t *) optdata);
+		break;
+	case LDAP_OPT_X_SASL_SSF:       /* read only */
+		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+		rc = -1;
+		break;
+#endif
+
+	default:
+		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+		rc = -1;
+	}
+
+	if ( ld != &nsldapi_ld_defaults ) {
+	    LDAP_MUTEX_UNLOCK( ld, LDAP_OPTION_LOCK );
+	}
+	return( rc );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/sort.c
@@ -0,0 +1,349 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ * Copyright (c) 1994 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+/*
+ * sort.c:  LDAP library entry and value sort routines
+ */
+
+#include "ldap-int.h"
+
+/* This xp_qsort fixes a memory problem (ABR) on Solaris for the client.
+ * Server is welcome to use it too, but I wasn't sure if it
+ * would be ok to use XP code here.  -slamm
+ *
+ * We don't want to require use of libxp when linking with libldap, so
+ * I'll leave use of xp_qsort as a MOZILLA_CLIENT-only thing for now. --mcs
+ */
+#if defined(MOZILLA_CLIENT) && defined(SOLARIS)
+#include "xp_qsort.h"
+#else
+#define XP_QSORT qsort
+#endif
+
+typedef struct keycmp {
+    void                 *kc_arg;
+    LDAP_KEYCMP_CALLBACK *kc_cmp;
+} keycmp_t;
+
+typedef struct keything {
+    keycmp_t            *kt_cmp;
+    const struct berval *kt_key;
+    LDAPMessage         *kt_msg;
+} keything_t;
+
+static int LDAP_C LDAP_CALLBACK
+ldapi_keycmp( const void *Lv, const void *Rv )
+{
+    auto keything_t **L = (keything_t**)Lv;
+    auto keything_t **R = (keything_t**)Rv;
+    auto keycmp_t *cmp = (*L)->kt_cmp;
+    return cmp->kc_cmp( cmp->kc_arg, (*L)->kt_key, (*R)->kt_key );
+}
+
+int
+LDAP_CALL
+ldap_keysort_entries(
+    LDAP        *ld,
+    LDAPMessage **chain,
+    void                  *arg,
+    LDAP_KEYGEN_CALLBACK  *gen,
+    LDAP_KEYCMP_CALLBACK  *cmp,
+    LDAP_KEYFREE_CALLBACK *fre)
+{
+	size_t		count, i;
+	keycmp_t	kc = {0};
+	keything_t	**kt;
+	LDAPMessage	*e, *last;
+	LDAPMessage	**ep;
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )
+	    || chain == NULL || cmp == NULL ) {
+		return( LDAP_PARAM_ERROR );
+	}
+
+	count = ldap_count_entries( ld, *chain );
+
+	if (count < 0) { /* error */
+		return( LDAP_PARAM_ERROR );
+	}
+
+	if (count < 2) { /* nothing to sort */
+		return( 0 );
+	}
+
+	kt = (keything_t**)NSLDAPI_MALLOC( count * (sizeof(keything_t*) + sizeof(keything_t)) );
+	if ( kt == NULL ) {
+		LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+		return( -1 );
+	}
+	for ( i = 0; i < count; i++ ) {
+		kt[i] = i + (keything_t*)(kt + count);
+	}
+	kc.kc_arg = arg;
+	kc.kc_cmp = cmp;
+
+	for ( e = *chain, i = 0; i < count; i++, e = e->lm_chain ) {
+		kt[i]->kt_msg = e;
+		kt[i]->kt_cmp = &kc;
+		kt[i]->kt_key = gen( arg, ld, e );
+		if ( kt[i]->kt_key == NULL ) {
+			if ( fre ) while ( i-- > 0 ) fre( arg, kt[i]->kt_key );
+			NSLDAPI_FREE( (char*)kt );
+			LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+			return( -1 );
+		}
+	}
+	last = e;
+
+	XP_QSORT( (void*)kt, count, (size_t)sizeof(keything_t*), ldapi_keycmp );
+    
+	ep = chain;
+	for ( i = 0; i < count; i++ ) {
+		*ep = kt[i]->kt_msg;
+		ep = &(*ep)->lm_chain;
+		if ( fre ) fre( arg, kt[i]->kt_key );
+	}
+	*ep = last;
+	NSLDAPI_FREE( (char*)kt );
+	return( 0 );
+}
+
+
+struct entrything {
+	char		**et_vals;
+	LDAPMessage	*et_msg;
+};
+
+typedef int (LDAP_C LDAP_CALLBACK LDAP_CHARCMP_CALLBACK)(char*, char*);
+typedef int (LDAP_C LDAP_CALLBACK LDAP_VOIDCMP_CALLBACK)(const void*, 
+	const void*);
+
+static LDAP_CHARCMP_CALLBACK *et_cmp_fn;
+static LDAP_VOIDCMP_CALLBACK et_cmp;
+
+int
+LDAP_C
+LDAP_CALLBACK
+ldap_sort_strcasecmp(
+    const char	**a,
+    const char	**b
+)
+{
+    /* XXXceb
+     * I am not 100% sure this is the way this should be handled.  
+     * For now we will return a 0 on invalid.
+     */    
+    if (NULL == a || NULL == b)
+        return (0);
+	return( strcasecmp( (char *)*a, (char *)*b ) );
+}
+
+static int
+LDAP_C
+LDAP_CALLBACK
+et_cmp(
+    const void	*aa,
+    const void	*bb
+)
+{
+	int			i, rc;
+	struct entrything	*a = (struct entrything *)aa;
+	struct entrything	*b = (struct entrything *)bb;
+
+	if ( a->et_vals == NULL && b->et_vals == NULL )
+		return( 0 );
+	if ( a->et_vals == NULL )
+		return( -1 );
+	if ( b->et_vals == NULL )
+		return( 1 );
+
+	for ( i = 0; a->et_vals[i] && b->et_vals[i]; i++ ) {
+		if ( (rc = (*et_cmp_fn)( a->et_vals[i], b->et_vals[i] ))
+		    != 0 ) {
+			return( rc );
+		}
+	}
+
+	if ( a->et_vals[i] == NULL && b->et_vals[i] == NULL )
+		return( 0 );
+	if ( a->et_vals[i] == NULL )
+		return( -1 );
+	return( 1 );
+}
+
+int
+LDAP_CALL
+ldap_multisort_entries(
+    LDAP	*ld,
+    LDAPMessage	**chain,
+    char	**attr,		/* NULL => sort by DN */
+    LDAP_CMP_CALLBACK *cmp
+)
+{
+	int			i, count;
+	struct entrything	*et;
+	LDAPMessage		*e, *last;
+	LDAPMessage		**ep;
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )
+	    || chain == NULL || cmp == NULL ) {
+		return( LDAP_PARAM_ERROR );
+	}
+
+	count = ldap_count_entries( ld, *chain );
+
+	if (count < 0) { /* error, usually with bad ld or malloc */
+		return( LDAP_PARAM_ERROR );
+	}
+
+	if (count < 2) { /* nothing to sort */
+		return( 0 );
+	}
+
+	if ( (et = (struct entrything *)NSLDAPI_MALLOC( count *
+	    sizeof(struct entrything) )) == NULL ) {
+		LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+		return( -1 );
+	}
+
+	e = *chain;
+	for ( i = 0; i < count; i++ ) {
+		et[i].et_msg = e;
+		et[i].et_vals = NULL;
+		if ( attr == NULL ) {
+			char	*dn;
+
+			dn = ldap_get_dn( ld, e );
+			et[i].et_vals = ldap_explode_dn( dn, 1 );
+			NSLDAPI_FREE( dn );
+		} else {
+			int	attrcnt;
+			char	**vals;
+
+			for ( attrcnt = 0; attr[attrcnt] != NULL; attrcnt++ ) {
+			    vals = ldap_get_values( ld, e, attr[attrcnt] );
+			    if ( ldap_charray_merge( &(et[i].et_vals), vals )
+				!= 0 ) {
+				int	j;
+
+				/* XXX risky: ldap_value_free( vals ); */
+				for ( j = 0; j <= i; j++ )
+				    ldap_value_free( et[j].et_vals );
+				NSLDAPI_FREE( (char *) et );
+				LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, 
+				    NULL );
+				return( -1 );
+			    }
+			    if ( vals != NULL ) {
+				NSLDAPI_FREE( (char *)vals );
+			    }
+			}
+		}
+
+		e = e->lm_chain;
+	}
+	last = e;
+
+	et_cmp_fn = (LDAP_CHARCMP_CALLBACK *)cmp;
+	XP_QSORT( (void *) et, (size_t) count,
+		(size_t) sizeof(struct entrything), et_cmp );
+
+	ep = chain;
+	for ( i = 0; i < count; i++ ) {
+		*ep = et[i].et_msg;
+		ep = &(*ep)->lm_chain;
+
+		ldap_value_free( et[i].et_vals );
+	}
+	*ep = last;
+	NSLDAPI_FREE( (char *) et );
+
+	return( 0 );
+}
+
+int
+LDAP_CALL
+ldap_sort_entries(
+    LDAP	*ld,
+    LDAPMessage	**chain,
+    char	*attr,		/* NULL => sort by DN */
+    LDAP_CMP_CALLBACK *cmp
+)
+{
+	char	*attrs[2];
+
+	attrs[0] = attr;
+	attrs[1] = NULL;
+	return( ldap_multisort_entries( ld, chain, attr ? attrs : NULL, cmp ) );
+}
+
+int
+LDAP_CALL
+ldap_sort_values(
+    LDAP	*ld,
+    char	**vals,
+    LDAP_VALCMP_CALLBACK *cmp
+)
+{
+	int	nel;
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) || cmp == NULL ) {
+		return( LDAP_PARAM_ERROR );
+	}
+
+    if ( NULL == vals) 
+    {
+		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+		return( LDAP_PARAM_ERROR );
+	}
+	for ( nel = 0; vals[nel] != NULL; nel++ )
+		;	/* NULL */
+
+	XP_QSORT( vals, nel, sizeof(char *), (LDAP_VOIDCMP_CALLBACK *)cmp );
+
+	return( LDAP_SUCCESS );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/sortctrl.c
@@ -0,0 +1,438 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+#include "ldap-int.h"
+
+/* ldap_create_sort_control:
+
+   Parameters are  
+
+   ld              LDAP pointer to the desired connection 
+
+   sortKeyList     an array of sortkeys 
+
+   ctl_iscritical  Indicates whether the control is critical of not. If
+                   this field is non-zero, the operation will only be car-
+                   ried out if the control is recognized by the server
+                   and/or client
+
+   ctrlp           the address of a place to put the constructed control 
+*/
+
+int
+LDAP_CALL
+ldap_create_sort_control ( 	
+     LDAP *ld, 
+     LDAPsortkey **sortKeyList,
+     const char ctl_iscritical,
+     LDAPControl **ctrlp   
+)
+{
+	BerElement		*ber;
+	int				i, rc;
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( LDAP_PARAM_ERROR );
+	}
+
+	if ( sortKeyList == NULL || ctrlp == NULL ) {
+		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+		return ( LDAP_PARAM_ERROR );
+	}
+
+	/* create a ber package to hold the controlValue */
+	if ( ( nsldapi_alloc_ber_with_options( ld, &ber ) ) != LDAP_SUCCESS ) {
+		LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+		return( LDAP_NO_MEMORY );
+	}
+
+	/* encode the start of the sequence of sequences into the ber */
+	if ( ber_printf( ber, "{" ) == -1 ) {
+		goto encoding_error_exit;
+	}
+
+	/* the sort control value will be encoded as a sequence of sequences
+	   which are each encoded as one of the following: {s} or {sts} or {stb} or {ststb} 
+	   since the orderingRule and reverseOrder flag are both optional */
+	for ( i = 0; sortKeyList[i] != NULL; i++ ) {
+
+		/* encode the attributeType into the ber */
+		if ( ber_printf( ber, "{s", (sortKeyList[i])->sk_attrtype  )
+		    == -1 ) {
+			goto encoding_error_exit;
+		}
+		
+		/* encode the optional orderingRule into the ber */
+		if ( (sortKeyList[i])->sk_matchruleoid != NULL ) {
+			if ( ber_printf( ber, "ts", LDAP_TAG_SK_MATCHRULE,
+			    (sortKeyList[i])->sk_matchruleoid )
+			    == -1 ) {
+				goto encoding_error_exit;
+			}
+		} 
+
+		/* Encode the optional reverseOrder flag into the ber. */
+		/* If the flag is false, it should be absent. */
+		if ( (sortKeyList[i])->sk_reverseorder ) {
+			if ( ber_printf( ber, "tb}", LDAP_TAG_SK_REVERSE,
+			    (sortKeyList[i])->sk_reverseorder ) == -1 ) {
+				goto encoding_error_exit;
+			}
+		} else {
+			if ( ber_printf( ber, "}" ) == -1 ) {
+				goto encoding_error_exit;
+			}
+		}
+	}
+
+	/* encode the end of the sequence of sequences into the ber */
+	if ( ber_printf( ber, "}" ) == -1 ) {
+		goto encoding_error_exit;
+	}
+
+	rc = nsldapi_build_control( LDAP_CONTROL_SORTREQUEST, ber, 1,
+	    ctl_iscritical, ctrlp );
+
+	LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+	return( rc );
+
+encoding_error_exit:
+	LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
+	ber_free( ber, 1 );
+	return( LDAP_ENCODING_ERROR );
+}
+
+/* ldap_parse_sort_control:
+
+   Parameters are  
+
+   ld              LDAP pointer to the desired connection 
+
+   ctrlp           An array of controls obtained from calling  
+                   ldap_parse_result on the set of results returned by 
+                   the server     
+
+   result          the address of a place to put the result code 
+
+   attribute       the address of a place to put the name of the 
+                   attribute which cause the operation to fail, optionally 
+                   returned by the server */
+
+int
+LDAP_CALL
+ldap_parse_sort_control ( 	
+     LDAP *ld, 
+     LDAPControl **ctrlp,  
+     ber_int_t *result,
+     char **attribute
+)
+{
+	BerElement *ber;
+	int			i, foundSortControl;
+	LDAPControl *sortCtrlp;
+	ber_len_t	len;
+	ber_tag_t	tag;
+	char		*attr;
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) || result == NULL ||
+		attribute == NULL ) {
+	    return( LDAP_PARAM_ERROR );
+	}
+
+
+	/* find the sortControl in the list of controls if it exists */
+	if ( ctrlp == NULL ) {
+		LDAP_SET_LDERRNO( ld, LDAP_CONTROL_NOT_FOUND, NULL, NULL );
+		return ( LDAP_CONTROL_NOT_FOUND );
+	} 
+	foundSortControl = 0;
+	for ( i = 0; (( ctrlp[i] != NULL ) && ( !foundSortControl )); i++ ) {
+		foundSortControl = !strcmp( ctrlp[i]->ldctl_oid, LDAP_CONTROL_SORTRESPONSE );
+	}
+	if ( !foundSortControl ) {
+		LDAP_SET_LDERRNO( ld, LDAP_CONTROL_NOT_FOUND, NULL, NULL );
+		return ( LDAP_CONTROL_NOT_FOUND );
+	} else {
+		/* let local var point to the sortControl */
+		sortCtrlp = ctrlp[i-1];			
+	}
+
+	/*  allocate a Ber element with the contents of the sort_control's struct berval */
+	if ( ( ber = ber_init( &sortCtrlp->ldctl_value ) ) == NULL ) {
+		LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+		return( LDAP_NO_MEMORY );
+	}		
+
+	/* decode the result from the Berelement */
+	if ( ber_scanf( ber, "{i", result ) == LBER_ERROR ) {
+		LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
+		ber_free( ber, 1 );
+		return( LDAP_DECODING_ERROR );
+	}
+
+	/* if the server returned one, decode the attribute from the Ber element */
+	if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SR_ATTRTYPE ) {
+		if ( ber_scanf( ber, "ta", &tag, &attr ) == LBER_ERROR ) {
+			LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
+			ber_free( ber, 1 );
+			return( LDAP_DECODING_ERROR );
+		}
+		*attribute = attr;		  
+	} else {
+		*attribute = NULL;
+	}
+
+	if ( ber_scanf( ber, "}" ) == LBER_ERROR ) {
+		LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
+		ber_free( ber, 1 );
+		return( LDAP_DECODING_ERROR );
+	}
+
+	/* the ber encoding is no longer needed */
+	ber_free(ber,1);
+
+	return( LDAP_SUCCESS );
+}
+
+/* Routines for the manipulation of string-representations of sort control keylists */
+
+static int count_tokens(const char *s)
+{
+	int count = 0;
+	const char *p = s;
+	int whitespace = 1;
+	/* Loop along the string counting the number of times we see the
+	 * beginning of non-whitespace. This tells us
+	 * the number of tokens in the string
+	 */
+	while (*p != '\0') {
+		if (whitespace) {
+			if (!isspace(*p)) {
+				whitespace = 0;
+				count++;
+			}
+		} else {
+			if (isspace(*p)) {
+				whitespace = 1;
+			}
+		}
+		p++;
+	}
+	return count;
+}
+
+
+static int read_next_token(const char **s,LDAPsortkey **key)
+{
+	char c = 0;
+	const char *pos = *s;
+	int retval = 0;
+	LDAPsortkey *new_key = NULL;
+
+	const char *matchrule_source = NULL;
+	int matchrule_size = 0;
+	const char *attrdesc_source = NULL;
+	int attrdesc_size = 0;
+	int reverse = 0;
+
+	int state = 0;
+	
+	while ( ((c = *pos++) != '\0') && (state != 4) ) {
+		switch (state) {
+		case 0:
+		/* case where we've not seen the beginning of the attr yet */
+			/* If we still see whitespace, nothing to do */
+			if (!isspace(c)) {
+				/* Otherwise, something to look at */
+				/* Is it a minus sign ? */
+				if ('-' == c) {
+					reverse = 1;
+				} else {
+					attrdesc_source = pos - 1;
+					state = 1;
+				}
+			}
+			break;
+		case 1:
+		/* case where we've seen the beginning of the attr, but not the end */
+			/* Is this char either whitespace or a ';' ? */
+			if ( isspace(c) || (':' == c)) {
+				attrdesc_size = (pos - attrdesc_source) - 1;
+				if (':' == c) {
+					state = 2;
+				} else {
+					state = 4;
+				}
+			} 
+			break;
+		case 2:
+		/* case where we've seen the end of the attr and want the beginning of match rule */
+			if (!isspace(c)) {
+				matchrule_source = pos - 1;
+				state = 3;
+			} else {
+				state = 4;
+			}
+			break;
+		case 3:
+		/* case where we've seen the beginning of match rule and want to find the end */
+			if (isspace(c)) {
+				matchrule_size = (pos - matchrule_source) - 1;
+				state = 4;
+			}
+			break;
+		default:
+			break;
+		}
+	}
+	
+	if (3 == state) {
+		/* means we fell off the end of the string looking for the end of the marching rule */
+		matchrule_size = (pos - matchrule_source) - 1;
+	}
+
+	if (1 == state) {
+		/* means we fell of the end of the string looking for the end of the attribute */
+		attrdesc_size = (pos - attrdesc_source) - 1;
+	}
+
+	if (NULL == attrdesc_source)  {
+		/* Didn't find anything */
+		return -1;
+	}
+
+	new_key = (LDAPsortkey*)NSLDAPI_MALLOC(sizeof(LDAPsortkey));
+	if (0 == new_key) {
+		return LDAP_NO_MEMORY;
+	}
+	
+	/* Allocate the strings */
+	new_key->sk_attrtype = (char *)NSLDAPI_MALLOC(attrdesc_size + 1);
+	if (NULL != matchrule_source) {
+		new_key->sk_matchruleoid = (char *)NSLDAPI_MALLOC(
+		    matchrule_size + 1);
+	} else {
+		new_key->sk_matchruleoid = NULL;
+	}
+	/* Copy over the strings */
+	memcpy(new_key->sk_attrtype,attrdesc_source,attrdesc_size);
+	*(new_key->sk_attrtype + attrdesc_size) = '\0';
+	if (NULL != matchrule_source) {
+		memcpy(new_key->sk_matchruleoid,matchrule_source,matchrule_size);
+		*(new_key->sk_matchruleoid + matchrule_size) = '\0';
+	}
+
+	new_key->sk_reverseorder = reverse;
+
+	*s = pos - 1;
+	*key = new_key;
+	return retval;
+}
+
+int
+LDAP_CALL
+ldap_create_sort_keylist (
+	LDAPsortkey ***sortKeyList,
+	const char *string_rep
+)
+{
+	int count = 0;
+	LDAPsortkey **pointer_array = NULL;
+	const char *current_position = NULL;
+	int retval = 0;
+	int i = 0;
+
+	/* Figure out how many there are */
+	if (NULL == string_rep) {
+		return LDAP_PARAM_ERROR;
+	}
+	if (NULL == sortKeyList) {
+		return LDAP_PARAM_ERROR;
+	}
+	count = count_tokens(string_rep);
+	if (0 == count) {
+		*sortKeyList = NULL;
+		return LDAP_PARAM_ERROR;
+	}
+	/* Allocate enough memory for the pointers */
+	pointer_array = (LDAPsortkey**)NSLDAPI_MALLOC(sizeof(LDAPsortkey*)
+	    * (count + 1) );
+	if (NULL == pointer_array) {
+		return LDAP_NO_MEMORY;
+	}
+	/* Now walk along the string, allocating and filling in the LDAPsearchkey structure */
+	current_position = string_rep;
+
+	for (i = 0; i < count; i++) {
+		if (0 != (retval = read_next_token(&current_position,&(pointer_array[i])))) {
+			pointer_array[count] = NULL;
+			ldap_free_sort_keylist(pointer_array);
+			*sortKeyList = NULL;
+			return retval;
+		}
+	}
+	pointer_array[count] = NULL;
+	*sortKeyList = pointer_array;
+	return LDAP_SUCCESS;
+}
+
+void
+LDAP_CALL
+ldap_free_sort_keylist (
+	LDAPsortkey **sortKeyList
+)
+{
+	LDAPsortkey *this_one = NULL;
+	int i = 0;
+
+	if ( NULL == sortKeyList ) {
+		return;
+	}
+
+	/* Walk down the list freeing the LDAPsortkey structures */
+	for (this_one = sortKeyList[0]; this_one ; this_one = sortKeyList[++i]) {
+		/* Free the strings, if present */
+		if (NULL != this_one->sk_attrtype) {
+			NSLDAPI_FREE(this_one->sk_attrtype);
+		}
+		if (NULL != this_one->sk_matchruleoid) {
+			NSLDAPI_FREE(this_one->sk_matchruleoid);
+		}
+		NSLDAPI_FREE(this_one);
+	}
+	/* Free the pointer list */
+	NSLDAPI_FREE(sortKeyList);
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/srchpref.c
@@ -0,0 +1,434 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ * Copyright (c) 1993, 1994 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ *
+ */
+/*
+ * searchpref.c:  search preferences library routines for LDAP clients
+ */
+
+#include "ldap-int.h"
+#include "srchpref.h"
+
+static void free_searchobj( struct ldap_searchobj *so );
+static int read_next_searchobj( char **bufp, long *blenp,
+	struct ldap_searchobj **sop, int soversion );
+
+
+static char		*sobjoptions[] = {
+    "internal",
+    NULL
+};
+
+
+static unsigned long	sobjoptvals[] = {
+    LDAP_SEARCHOBJ_OPT_INTERNAL,
+};
+
+
+int
+LDAP_CALL
+ldap_init_searchprefs( char *file, struct ldap_searchobj **solistp )
+{
+    FILE	*fp;
+    char	*buf;
+    long	rlen, len;
+    int		rc, eof;
+
+    if (( fp = NSLDAPI_FOPEN( file, "r" )) == NULL ) {
+	return( LDAP_SEARCHPREF_ERR_FILE );
+    }
+
+    if ( fseek( fp, 0L, SEEK_END ) != 0 ) {	/* move to end to get len */
+	fclose( fp );
+	return( LDAP_SEARCHPREF_ERR_FILE );
+    }
+
+    len = ftell( fp );
+
+    if ( fseek( fp, 0L, SEEK_SET ) != 0 ) {	/* back to start of file */
+	fclose( fp );
+	return( LDAP_SEARCHPREF_ERR_FILE );
+    }
+
+    if (( buf = NSLDAPI_MALLOC( (size_t)len )) == NULL ) {
+	fclose( fp );
+	return( LDAP_SEARCHPREF_ERR_MEM );
+    }
+
+    rlen = fread( buf, 1, (size_t)len, fp );
+    eof = feof( fp );
+    fclose( fp );
+
+    if ( rlen != len && !eof ) {	/* error:  didn't get the whole file */
+	NSLDAPI_FREE( buf );
+	return( LDAP_SEARCHPREF_ERR_FILE );
+    }
+
+    rc = ldap_init_searchprefs_buf( buf, rlen, solistp );
+    NSLDAPI_FREE( buf );
+
+    return( rc );
+}
+
+
+int
+LDAP_CALL
+ldap_init_searchprefs_buf( char *buf, long buflen,
+	struct ldap_searchobj **solistp )
+{
+    int				rc = 0, version;
+    char			**toks;
+    struct ldap_searchobj	*prevso, *so;
+
+    *solistp = prevso = NULLSEARCHOBJ;
+
+    if ( nsldapi_next_line_tokens( &buf, &buflen, &toks ) != 2 ||
+	    strcasecmp( toks[ 0 ], "version" ) != 0 ) {
+	nsldapi_free_strarray( toks );
+	return( LDAP_SEARCHPREF_ERR_SYNTAX );
+    }
+    version = atoi( toks[ 1 ] );
+    nsldapi_free_strarray( toks );
+    if ( version != LDAP_SEARCHPREF_VERSION &&
+	    version != LDAP_SEARCHPREF_VERSION_ZERO ) {
+	return( LDAP_SEARCHPREF_ERR_VERSION );
+    }
+
+    while ( buflen > 0 && ( rc = read_next_searchobj( &buf, &buflen, &so,
+	    version )) == 0 && so != NULLSEARCHOBJ ) {
+	if ( prevso == NULLSEARCHOBJ ) {
+	    *solistp = so;
+	} else {
+	    prevso->so_next = so;
+	}
+	prevso = so;
+    }
+
+    if ( rc != 0 ) {
+	ldap_free_searchprefs( *solistp );
+    }
+
+    return( rc );
+}
+	    
+
+
+void
+LDAP_CALL
+ldap_free_searchprefs( struct ldap_searchobj *solist )
+{
+    struct ldap_searchobj	*so, *nextso;
+
+    if ( solist != NULL ) {
+	for ( so = solist; so != NULL; so = nextso ) {
+	    nextso = so->so_next;
+	    free_searchobj( so );
+	}
+    }
+    /* XXX XXX need to do some work here */
+}
+
+
+static void
+free_searchobj( struct ldap_searchobj *so )
+{
+    if ( so != NULL ) {
+	if ( so->so_objtypeprompt != NULL ) {
+	    NSLDAPI_FREE(  so->so_objtypeprompt );
+	}
+	if ( so->so_prompt != NULL ) {
+	    NSLDAPI_FREE(  so->so_prompt );
+	}
+	if ( so->so_filterprefix != NULL ) {
+	    NSLDAPI_FREE(  so->so_filterprefix );
+	}
+	if ( so->so_filtertag != NULL ) {
+	    NSLDAPI_FREE(  so->so_filtertag );
+	}
+	if ( so->so_defaultselectattr != NULL ) {
+	    NSLDAPI_FREE(  so->so_defaultselectattr );
+	}
+	if ( so->so_defaultselecttext != NULL ) {
+	    NSLDAPI_FREE(  so->so_defaultselecttext );
+	}
+	if ( so->so_salist != NULL ) {
+	    struct ldap_searchattr *sa, *nextsa;
+	    for ( sa = so->so_salist; sa != NULL; sa = nextsa ) {
+		nextsa = sa->sa_next;
+		if ( sa->sa_attrlabel != NULL ) {
+		    NSLDAPI_FREE( sa->sa_attrlabel );
+		}
+		if ( sa->sa_attr != NULL ) {
+		    NSLDAPI_FREE( sa->sa_attr );
+		}
+		if ( sa->sa_selectattr != NULL ) {
+		    NSLDAPI_FREE( sa->sa_selectattr );
+		}
+		if ( sa->sa_selecttext != NULL ) {
+		    NSLDAPI_FREE( sa->sa_selecttext );
+		}
+		NSLDAPI_FREE( sa );
+	    }
+	}
+	if ( so->so_smlist != NULL ) {
+	    struct ldap_searchmatch *sm, *nextsm;
+	    for ( sm = so->so_smlist; sm != NULL; sm = nextsm ) {
+		nextsm = sm->sm_next;
+		if ( sm->sm_matchprompt != NULL ) {
+		    NSLDAPI_FREE( sm->sm_matchprompt );
+		}
+		if ( sm->sm_filter != NULL ) {
+		    NSLDAPI_FREE( sm->sm_filter );
+		}
+		NSLDAPI_FREE( sm );
+	    }
+	}
+	NSLDAPI_FREE( so );
+    }
+}
+
+
+
+struct ldap_searchobj *
+LDAP_CALL
+ldap_first_searchobj( struct ldap_searchobj *solist )
+{
+    return( solist );
+}
+
+
+struct ldap_searchobj *
+LDAP_CALL
+ldap_next_searchobj( struct ldap_searchobj *solist, struct ldap_searchobj *so )
+{
+    return( so == NULLSEARCHOBJ ? so : so->so_next );
+}
+
+
+
+static int
+read_next_searchobj( char **bufp, long *blenp, struct ldap_searchobj **sop,
+	int soversion )
+{
+    int				i, j, tokcnt;
+    char			**toks;
+    struct ldap_searchobj	*so;
+    struct ldap_searchattr	**sa;
+    struct ldap_searchmatch	**sm;
+
+    *sop = NULL;
+
+    /*
+     * Object type prompt comes first
+     */
+    if (( tokcnt = nsldapi_next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+	nsldapi_free_strarray( toks );
+	return( tokcnt == 0 ? 0 : LDAP_SEARCHPREF_ERR_SYNTAX );
+    }
+
+    if (( so = (struct ldap_searchobj *)NSLDAPI_CALLOC( 1,
+	    sizeof( struct ldap_searchobj ))) == NULL ) {
+	nsldapi_free_strarray( toks );
+	return(  LDAP_SEARCHPREF_ERR_MEM );
+    }
+    so->so_objtypeprompt = toks[ 0 ];
+    NSLDAPI_FREE( (char *)toks );
+
+    /*
+     * if this is post-version zero, options come next
+     */
+    if ( soversion > LDAP_SEARCHPREF_VERSION_ZERO ) {
+	if (( tokcnt = nsldapi_next_line_tokens( bufp, blenp, &toks )) < 1 ) {
+	    nsldapi_free_strarray( toks );
+	    ldap_free_searchprefs( so );
+	    return( LDAP_SEARCHPREF_ERR_SYNTAX );
+	}
+	for ( i = 0; toks[ i ] != NULL; ++i ) {
+	    for ( j = 0; sobjoptions[ j ] != NULL; ++j ) {
+		if ( strcasecmp( toks[ i ], sobjoptions[ j ] ) == 0 ) {
+		    so->so_options |= sobjoptvals[ j ];
+		}
+	    }
+	}
+	nsldapi_free_strarray( toks );
+    }
+
+    /*
+     * "Fewer choices" prompt is next
+     */
+    if (( tokcnt = nsldapi_next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+	nsldapi_free_strarray( toks );
+	ldap_free_searchprefs( so );
+	return( LDAP_SEARCHPREF_ERR_SYNTAX );
+    }
+    so->so_prompt = toks[ 0 ];
+    NSLDAPI_FREE( (char *)toks );
+
+    /*
+     * Filter prefix for "More Choices" searching is next
+     */
+    if (( tokcnt = nsldapi_next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+	nsldapi_free_strarray( toks );
+	ldap_free_searchprefs( so );
+	return( LDAP_SEARCHPREF_ERR_SYNTAX );
+    }
+    so->so_filterprefix = toks[ 0 ];
+    NSLDAPI_FREE( (char *)toks );
+
+    /*
+     * "Fewer Choices" filter tag comes next
+     */
+    if (( tokcnt = nsldapi_next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+	nsldapi_free_strarray( toks );
+	ldap_free_searchprefs( so );
+	return( LDAP_SEARCHPREF_ERR_SYNTAX );
+    }
+    so->so_filtertag = toks[ 0 ];
+    NSLDAPI_FREE( (char *)toks );
+
+    /*
+     * Selection (disambiguation) attribute comes next
+     */
+    if (( tokcnt = nsldapi_next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+	nsldapi_free_strarray( toks );
+	ldap_free_searchprefs( so );
+	return( LDAP_SEARCHPREF_ERR_SYNTAX );
+    }
+    so->so_defaultselectattr = toks[ 0 ];
+    NSLDAPI_FREE( (char *)toks );
+
+    /*
+     * Label for selection (disambiguation) attribute
+     */
+    if (( tokcnt = nsldapi_next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+	nsldapi_free_strarray( toks );
+	ldap_free_searchprefs( so );
+	return( LDAP_SEARCHPREF_ERR_SYNTAX );
+    }
+    so->so_defaultselecttext = toks[ 0 ];
+    NSLDAPI_FREE( (char *)toks );
+
+    /*
+     * Search scope is next
+     */
+    if (( tokcnt = nsldapi_next_line_tokens( bufp, blenp, &toks )) != 1 ) {
+	nsldapi_free_strarray( toks );
+	ldap_free_searchprefs( so );
+	return( LDAP_SEARCHPREF_ERR_SYNTAX );
+    }
+    if ( !strcasecmp(toks[ 0 ], "subtree" )) {
+	so->so_defaultscope = LDAP_SCOPE_SUBTREE;
+    } else if ( !strcasecmp(toks[ 0 ], "onelevel" )) {
+	so->so_defaultscope = LDAP_SCOPE_ONELEVEL;
+    } else if ( !strcasecmp(toks[ 0 ], "base" )) {
+	so->so_defaultscope = LDAP_SCOPE_BASE;
+    } else {
+	ldap_free_searchprefs( so );
+	return( LDAP_SEARCHPREF_ERR_SYNTAX );
+    }
+    nsldapi_free_strarray( toks );
+
+
+    /*
+     * "More Choices" search option list comes next
+     */
+    sa = &( so->so_salist );
+    while (( tokcnt = nsldapi_next_line_tokens( bufp, blenp, &toks )) > 0 ) {
+	if ( tokcnt < 5 ) {
+	    nsldapi_free_strarray( toks );
+	    ldap_free_searchprefs( so );
+	    return( LDAP_SEARCHPREF_ERR_SYNTAX );
+	}
+	if (( *sa = ( struct ldap_searchattr * )NSLDAPI_CALLOC( 1,
+		sizeof( struct ldap_searchattr ))) == NULL ) {
+	    nsldapi_free_strarray( toks );
+	    ldap_free_searchprefs( so );
+	    return(  LDAP_SEARCHPREF_ERR_MEM );
+	}
+	( *sa )->sa_attrlabel = toks[ 0 ];
+	( *sa )->sa_attr = toks[ 1 ];
+	( *sa )->sa_selectattr = toks[ 3 ];
+	( *sa )->sa_selecttext = toks[ 4 ];
+	/* Deal with bitmap */
+	( *sa )->sa_matchtypebitmap = 0;
+	for ( i = strlen( toks[ 2 ] ) - 1, j = 0; i >= 0; i--, j++ ) {
+	    if ( toks[ 2 ][ i ] == '1' ) {
+		( *sa )->sa_matchtypebitmap |= (1 << j);
+	    }
+	}
+	NSLDAPI_FREE( toks[ 2 ] );
+	NSLDAPI_FREE( ( char * ) toks );
+	sa = &(( *sa )->sa_next);
+    }
+    *sa = NULL;
+
+    /*
+     * Match types are last
+     */
+    sm = &( so->so_smlist );
+    while (( tokcnt = nsldapi_next_line_tokens( bufp, blenp, &toks )) > 0 ) {
+	if ( tokcnt < 2 ) {
+	    nsldapi_free_strarray( toks );
+	    ldap_free_searchprefs( so );
+	    return( LDAP_SEARCHPREF_ERR_SYNTAX );
+	}
+	if (( *sm = ( struct ldap_searchmatch * )NSLDAPI_CALLOC( 1,
+		sizeof( struct ldap_searchmatch ))) == NULL ) {
+	    nsldapi_free_strarray( toks );
+	    ldap_free_searchprefs( so );
+	    return(  LDAP_SEARCHPREF_ERR_MEM );
+	}
+	( *sm )->sm_matchprompt = toks[ 0 ];
+	( *sm )->sm_filter = toks[ 1 ];
+	NSLDAPI_FREE( ( char * ) toks );
+	sm = &(( *sm )->sm_next );
+    }
+    *sm = NULL;
+
+    *sop = so;
+    return( 0 );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/test.c
@@ -0,0 +1,1898 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+/* test.c - a simple test harness. */
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#ifdef MACOS
+#ifdef THINK_C
+#include <console.h>
+#include <unix.h>
+#include <fcntl.h>
+#endif /* THINK_C */
+#include "macos.h"
+#else /* MACOS */
+#if defined( DOS )
+#include "msdos.h"
+#if defined( WINSOCK ) 
+#include "console.h"
+#endif /* WINSOCK */
+#else /* DOS */
+#ifdef _WINDOWS
+#include <windows.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+//#include "console.h"
+#else /* _WINDOWS */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#ifndef VMS
+#include <fcntl.h>
+#include <unistd.h>
+#endif /* VMS */
+#endif /* _WINDOWS */
+#endif /* DOS */
+#endif /* MACOS */
+
+#include "ldap.h"
+#include "disptmpl.h"
+#include "ldaplog.h"
+#include "portable.h"
+#ifndef NO_LIBLCACHE
+#include "lcache.h"
+#endif /* !NO_LIBLCACHE */
+
+#undef NET_SSL
+#if defined(NET_SSL)
+#include <nss.h>
+#include <ldap_ssl.h>
+#endif
+
+
+#if !defined( PCNFS ) && !defined( WINSOCK ) && !defined( MACOS )
+#define MOD_USE_BVALS
+#endif /* !PCNFS && !WINSOCK && !MACOS */
+
+static void handle_result( LDAP *ld, LDAPMessage *lm, int onlyone );
+static void print_ldap_result( LDAP *ld, LDAPMessage *lm, char *s );
+static void print_controls( LDAPControl **ctrls, int freeit );
+static void print_referrals( char **refs, int freeit );
+static void print_search_entry( LDAP *ld, LDAPMessage *res, int onlyone );
+static char *changetype_num2string( ber_int_t chgtype );
+static void print_search_reference( LDAP *ld, LDAPMessage *res, int onlyone );
+static void free_list( char **list );
+static int entry2textwrite( void *fp, char *buf, int len );
+static void bprint( char *data, int len );
+static char **string2words( char *str, char *delims );
+static const char * url_parse_err2string( int e );
+
+char *dnsuffix;
+
+#ifndef WINSOCK
+static char *
+getline( char *line, int len, FILE *fp, char *prompt )
+{
+	printf(prompt);
+
+	if ( fgets( line, len, fp ) == NULL )
+		return( NULL );
+
+	line[ strlen( line ) - 1 ] = '\0';
+
+	return( line );
+}
+#endif /* WINSOCK */
+
+static char **
+get_list( char *prompt )
+{
+	static char	buf[256];
+	int		num;
+	char		**result;
+
+	num = 0;
+	result = (char **) 0;
+	while ( 1 ) {
+		getline( buf, sizeof(buf), stdin, prompt );
+
+		if ( *buf == '\0' )
+			break;
+
+		if ( result == (char **) 0 )
+			result = (char **) malloc( sizeof(char *) );
+		else
+			result = (char **) realloc( result,
+			    sizeof(char *) * (num + 1) );
+
+		result[num++] = (char *) strdup( buf );
+	}
+	if ( result == (char **) 0 )
+		return( NULL );
+	result = (char **) realloc( result, sizeof(char *) * (num + 1) );
+	result[num] = NULL;
+
+	return( result );
+}
+
+
+static void
+free_list( char **list )
+{
+	int	i;
+
+	if ( list != NULL ) {
+		for ( i = 0; list[ i ] != NULL; ++i ) {
+			free( list[ i ] );
+		}
+		free( (char *)list );
+	}
+}
+
+
+#ifdef MOD_USE_BVALS
+static int
+file_read( char *path, struct berval *bv )
+{
+	FILE		*fp;
+	long		rlen;
+	int		eof;
+
+	if (( fp = NSLDAPI_FOPEN( path, "r" )) == NULL ) {
+	    	perror( path );
+		return( -1 );
+	}
+
+	if ( fseek( fp, 0L, SEEK_END ) != 0 ) {
+		perror( path );
+		fclose( fp );
+		return( -1 );
+	}
+
+	bv->bv_len = ftell( fp );
+
+	if (( bv->bv_val = (char *)malloc( bv->bv_len )) == NULL ) {
+		perror( "malloc" );
+		fclose( fp );
+		return( -1 );
+	}
+
+	if ( fseek( fp, 0L, SEEK_SET ) != 0 ) {
+		perror( path );
+		fclose( fp );
+		return( -1 );
+	}
+
+	rlen = fread( bv->bv_val, 1, bv->bv_len, fp );
+	eof = feof( fp );
+	fclose( fp );
+
+	if ( (unsigned long)rlen != bv->bv_len ) {
+		perror( path );
+		free( bv->bv_val );
+		return( -1 );
+	}
+
+	return( bv->bv_len );
+}
+#endif /* MOD_USE_BVALS */
+
+
+static LDAPMod **
+get_modlist( char *prompt1, char *prompt2, char *prompt3 )
+{
+	static char	buf[256];
+	int		num;
+	LDAPMod		tmp;
+	LDAPMod		**result;
+#ifdef MOD_USE_BVALS
+	struct berval	**bvals;
+#endif /* MOD_USE_BVALS */
+
+	num = 0;
+	result = NULL;
+	while ( 1 ) {
+		if ( prompt1 ) {
+			getline( buf, sizeof(buf), stdin, prompt1 );
+			tmp.mod_op = atoi( buf );
+
+			if ( tmp.mod_op == -1 || buf[0] == '\0' )
+				break;
+		} else {
+			tmp.mod_op = 0;
+		}
+
+		getline( buf, sizeof(buf), stdin, prompt2 );
+		if ( buf[0] == '\0' )
+			break;
+		tmp.mod_type = strdup( buf );
+
+		tmp.mod_values = get_list( prompt3 );
+#ifdef MOD_USE_BVALS
+		if ( tmp.mod_values != NULL ) {
+			int	i;
+
+			for ( i = 0; tmp.mod_values[i] != NULL; ++i )
+				;
+			bvals = (struct berval **)calloc( i + 1,
+			    sizeof( struct berval *));
+			for ( i = 0; tmp.mod_values[i] != NULL; ++i ) {
+				bvals[i] = (struct berval *)malloc(
+				    sizeof( struct berval ));
+				if ( strncmp( tmp.mod_values[i], "{FILE}",
+				    6 ) == 0 ) {
+					if ( file_read( tmp.mod_values[i] + 6,
+					    bvals[i] ) < 0 ) {
+						return( NULL );
+					}
+				} else {
+					bvals[i]->bv_val = tmp.mod_values[i];
+					bvals[i]->bv_len =
+					    strlen( tmp.mod_values[i] );
+				}
+			}
+			tmp.mod_bvalues = bvals;
+			tmp.mod_op |= LDAP_MOD_BVALUES;
+		}
+#endif /* MOD_USE_BVALS */
+
+		if ( result == NULL )
+			result = (LDAPMod **) malloc( sizeof(LDAPMod *) );
+		else
+			result = (LDAPMod **) realloc( result,
+			    sizeof(LDAPMod *) * (num + 1) );
+
+		result[num] = (LDAPMod *) malloc( sizeof(LDAPMod) );
+		*(result[num]) = tmp;	/* struct copy */
+		num++;
+	}
+	if ( result == NULL )
+		return( NULL );
+	result = (LDAPMod **) realloc( result, sizeof(LDAPMod *) * (num + 1) );
+	result[num] = NULL;
+
+	return( result );
+}
+
+
+int LDAP_CALL LDAP_CALLBACK
+bind_prompt( LDAP *ld, char **dnp, char **passwdp, int *authmethodp,
+	int freeit, void *dummy )
+{
+	static char	dn[256], passwd[256];
+
+	if ( !freeit ) {
+#ifdef KERBEROS
+		getline( dn, sizeof(dn), stdin,
+		    "re-bind method (0->simple, 1->krbv41, 2->krbv42, 3->krbv41&2)? " );
+		if (( *authmethodp = atoi( dn )) == 3 ) {
+			*authmethodp = LDAP_AUTH_KRBV4;
+		} else {
+			*authmethodp |= 0x80;
+		}
+#else /* KERBEROS */
+		*authmethodp = LDAP_AUTH_SIMPLE;
+#endif /* KERBEROS */
+
+		getline( dn, sizeof(dn), stdin, "re-bind dn? " );
+		strcat( dn, dnsuffix );
+		*dnp = dn;
+
+		if ( *authmethodp == LDAP_AUTH_SIMPLE && dn[0] != '\0' ) {
+			getline( passwd, sizeof(passwd), stdin,
+			    "re-bind password? " );
+		} else {
+			passwd[0] = '\0';
+		}
+		*passwdp = passwd;
+	}
+
+	return( LDAP_SUCCESS );
+}
+
+
+#define HEX2BIN( h )	( (h) >= '0' && (h) <='9' ? (h) - '0' : (h) - 'A' + 10 )
+
+void
+berval_from_hex( struct berval *bvp, char *hexstr )
+{
+    char	*src, *dst, c;
+	unsigned char abyte;
+
+    dst = bvp->bv_val;
+    bvp->bv_len = 0;
+    src = hexstr;
+    while ( *src != '\0' ) {
+	c = *src;
+	if ( isupper( c )) {
+		c = tolower( c );
+	}
+	abyte = HEX2BIN( c ) << 4;
+
+	++src;
+	c = *src;
+	if ( isupper( c )) {
+		c = tolower( c );
+	}
+	abyte |= HEX2BIN( c );
+	++src;
+
+	*dst++ = abyte;
+	++bvp->bv_len;
+    }
+}
+
+
+static void
+add_control( LDAPControl ***ctrlsp, LDAPControl *newctrl )
+{
+	int	i;
+
+	if ( *ctrlsp == NULL ) {
+		*ctrlsp = (LDAPControl **) calloc( 2, sizeof(LDAPControl *) );
+		i = 0;
+	} else {
+		for ( i = 0; (*ctrlsp)[i] != NULL; i++ ) {
+			;	/* NULL */
+		}
+		*ctrlsp = (LDAPControl **) realloc( *ctrlsp,
+		    (i + 2) * sizeof(LDAPControl *) );
+	}
+	(*ctrlsp)[i] = newctrl;
+	(*ctrlsp)[i+1] = NULL;
+}
+
+
+#ifdef TEST_CUSTOM_MALLOC
+
+typedef struct my_malloc_info {
+	long	mmi_magic;
+	size_t	mmi_actualsize;
+} MyMallocInfo;
+#define MY_MALLOC_MAGIC_NUMBER		0x19940618
+
+#define MY_MALLOC_CHECK_MAGIC( p )	if ( ((MyMallocInfo *)( (p) - sizeof()
+
+void *
+my_malloc( size_t size )
+{
+	void		*p;
+	MyMallocInfo	*mmip;
+
+	if (( p = malloc( size + sizeof( struct my_malloc_info ))) != NULL ) {
+		mmip = (MyMallocInfo *)p;
+		mmip->mmi_magic = MY_MALLOC_MAGIC_NUMBER;
+		mmip->mmi_actualsize = size;
+	}
+
+	fprintf( stderr, "my_malloc: allocated ptr 0x%x, size %ld\n",
+	    p,  mmip->mmi_actualsize );
+
+	return( (char *)p + sizeof( MyMallocInfo ));
+}
+
+
+void *
+my_calloc( size_t nelem, size_t elsize )
+{
+	void	*p;
+
+	if (( p = my_malloc( nelem * elsize )) != NULL ) {
+		memset( p, 0, nelem * elsize );
+	}
+
+	return( p );
+}
+
+
+void
+my_free( void *ptr )
+{
+	char		*p;
+	MyMallocInfo	*mmip;
+
+	p = (char *)ptr;
+	p -= sizeof( MyMallocInfo );
+	mmip = (MyMallocInfo *)p;
+	if ( mmip->mmi_magic != MY_MALLOC_MAGIC_NUMBER ) {
+		fprintf( stderr,
+		    "my_malloc_check_magic: ptr 0x%x bad magic number\n", ptr );
+		exit( 1 );
+	}
+
+	fprintf( stderr, "my_free: freeing ptr 0x%x, size %ld\n",
+	    p,  mmip->mmi_actualsize );
+
+	memset( p, 0, mmip->mmi_actualsize + sizeof( MyMallocInfo ));
+	free( p );
+}
+
+
+void *
+my_realloc( void *ptr, size_t size )
+{
+	void		*p;
+	MyMallocInfo	*mmip;
+
+	if ( ptr == NULL ) {
+		return( my_malloc( size ));
+	}
+
+	mmip = (MyMallocInfo *)( (char *)ptr - sizeof( MyMallocInfo ));
+	if ( mmip->mmi_magic != MY_MALLOC_MAGIC_NUMBER ) {
+		fprintf( stderr,
+		    "my_malloc_check_magic: ptr 0x%x bad magic number\n", ptr );
+		exit( 1 );
+	}
+
+	if ( size <= mmip->mmi_actualsize ) {	/* current block big enough? */
+		return( ptr );
+	}
+
+	if (( p = my_malloc( size )) != NULL ) {
+		memcpy( p, ptr, mmip->mmi_actualsize );
+		my_free( ptr );
+	}
+
+	return( p );
+}
+#endif /* TEST_CUSTOM_MALLOC */
+
+int
+#ifdef WINSOCK
+ldapmain(
+#else /* WINSOCK */
+main(
+#endif /* WINSOCK */
+	int argc, char **argv )
+{
+	LDAP		*ld;
+	int		rc, i, c, port, cldapflg, errflg, method, id, msgtype;
+	int		version;
+	char		line[256], command1, command2, command3;
+	char		passwd[64], dn[256], rdn[64], attr[64], value[256];
+	char		filter[256], *host, **types;
+	char		**exdn, *fnname;
+	int		bound, all, scope, attrsonly, optval, ldapversion;
+	LDAPMessage	*res;
+	LDAPMod		**mods, **attrs;
+	struct timeval	timeout, *tvp;
+	char		*copyfname = NULL;
+	int		copyoptions = 0;
+	LDAPURLDesc	*ludp;
+	struct ldap_disptmpl	*tmpllist = NULL;
+	int		changetypes, changesonly, return_echg_ctls;
+	LDAPControl	**tmpctrls, *newctrl, **controls = NULL;
+	char		*usage = "usage: %s [-u] [-h host] [-d level] [-s dnsuffix] [-p port] [-t file] [-T file] [-V protocolversion]\n";
+
+	extern char	*optarg;
+	extern int	optind;
+
+#ifdef MACOS
+	if (( argv = get_list( "cmd line arg?" )) == NULL ) {
+		exit( 1 );
+	}
+	for ( argc = 0; argv[ argc ] != NULL; ++argc ) {
+		;
+	}
+#endif /* MACOS */
+
+#ifdef TEST_CUSTOM_MALLOC
+        {
+		struct ldap_memalloc_fns	memalloc_fns;
+
+		memalloc_fns.ldapmem_malloc = my_malloc;
+		memalloc_fns.ldapmem_calloc = my_calloc;
+		memalloc_fns.ldapmem_realloc = my_realloc;
+		memalloc_fns.ldapmem_free = my_free;
+
+		if ( ldap_set_option( NULL, LDAP_OPT_MEMALLOC_FN_PTRS,
+		    &memalloc_fns ) != 0 ) {
+			fputs( "ldap_set_option failed\n", stderr );
+			exit( 1 );
+		}
+	}
+#endif /* TEST_CUSTOM_MALLOC */
+
+	host = NULL;
+	port = LDAP_PORT;
+	dnsuffix = "";
+	cldapflg = errflg = 0;
+	ldapversion = 0;	/* use default */
+#ifndef _WIN32
+#ifdef LDAP_DEBUG
+	ldap_debug = LDAP_DEBUG_ANY;
+#endif
+#endif
+
+	while (( c = getopt( argc, argv, "uh:d:s:p:t:T:V:" )) != -1 ) {
+		switch( c ) {
+		case 'u':
+#ifdef CLDAP
+			cldapflg++;
+#else /* CLDAP */
+			printf( "Compile with -DCLDAP for UDP support\n" );
+#endif /* CLDAP */
+			break;
+
+		case 'd':
+#ifndef _WIN32
+#ifdef LDAP_DEBUG
+			ldap_debug = atoi( optarg ) | LDAP_DEBUG_ANY;
+			if ( ldap_debug & LDAP_DEBUG_PACKETS ) {
+				ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL,
+					&ldap_debug );
+			}
+#else
+			printf( "Compile with -DLDAP_DEBUG for debugging\n" );
+#endif
+#endif
+			break;
+
+		case 'h':
+			host = optarg;
+			break;
+
+		case 's':
+			dnsuffix = optarg;
+			break;
+
+		case 'p':
+			port = atoi( optarg );
+			break;
+
+#if !defined(MACOS) && !defined(DOS)
+		case 't':	/* copy ber's to given file */
+			copyfname = strdup( optarg );
+			copyoptions = LBER_SOCKBUF_OPT_TO_FILE;
+			break;
+
+		case 'T':	/* only output ber's to given file */
+			copyfname = strdup( optarg );
+			copyoptions = (LBER_SOCKBUF_OPT_TO_FILE |
+			    LBER_SOCKBUF_OPT_TO_FILE_ONLY);
+			break;
+#endif
+		case 'V':	/* LDAP protocol version */
+			ldapversion = atoi( optarg );
+			break;
+
+		default:
+		    ++errflg;
+		}
+	}
+
+	if ( host == NULL && optind == argc - 1 ) {
+		host = argv[ optind ];
+		++optind;
+	}
+
+	if ( errflg || optind < argc - 1 ) {
+		fprintf( stderr, usage, argv[ 0 ] );
+		exit( 1 );
+	}
+	
+	printf( "%sldap_init( %s, %d )\n", cldapflg ? "c" : "",
+		host == NULL ? "(null)" : host, port );
+
+	if ( cldapflg ) {
+#ifdef CLDAP
+		ld = cldap_open( host, port );
+#endif /* CLDAP */
+	} else {
+		ld = ldap_init( host, port );
+	}
+
+	if ( ld == NULL ) {
+		perror( "ldap_init" );
+		exit(1);
+	}
+
+	if ( ldapversion != 0 && ldap_set_option( ld,
+	    LDAP_OPT_PROTOCOL_VERSION, (void *)&ldapversion ) != 0 ) {
+		ldap_perror( ld, "ldap_set_option (protocol version)" );
+		exit(1);
+	}
+
+#ifdef notdef
+#if !defined(MACOS) && !defined(DOS)
+	if ( copyfname != NULL ) {
+		int	fd;
+		Sockbuf	*sb;
+
+		if ( (fd = open( copyfname, O_WRONLY | O_CREAT, 0600 ))
+		    == -1 ) {
+			perror( copyfname );
+			exit ( 1 );
+		}
+		ldap_get_option( ld, LDAP_OPT_SOCKBUF, &sb );
+		ber_sockbuf_set_option( sb, LBER_SOCKBUF_OPT_COPYDESC,
+		    (void *) &fd );
+		ber_sockbuf_set_option( sb, copyoptions, LBER_OPT_ON );
+	}
+#endif
+#endif
+
+	bound = 0;
+	timeout.tv_sec = 0;
+	timeout.tv_usec = 0;
+	tvp = &timeout;
+
+	(void) memset( line, '\0', sizeof(line) );
+	while ( getline( line, sizeof(line), stdin, "\ncommand? " ) != NULL ) {
+		command1 = line[0];
+		command2 = line[1];
+		command3 = line[2];
+
+		switch ( command1 ) {
+		case 'a':	/* add or abandon */
+			switch ( command2 ) {
+			case 'd':	/* add */
+				getline( dn, sizeof(dn), stdin, "dn? " );
+				strcat( dn, dnsuffix );
+				if ( (attrs = get_modlist( NULL, "attr? ",
+				    "value? " )) == NULL )
+					break;
+				if ( (id = ldap_add( ld, dn, attrs )) == -1 )
+					ldap_perror( ld, "ldap_add" );
+				else
+					printf( "Add initiated with id %d\n",
+					    id );
+				break;
+
+			case 'b':	/* abandon */
+				getline( line, sizeof(line), stdin, "msgid? " );
+				id = atoi( line );
+				if ( ldap_abandon( ld, id ) != 0 )
+					ldap_perror( ld, "ldap_abandon" );
+				else
+					printf( "Abandon successful\n" );
+				break;
+			default:
+				printf( "Possibilities: [ad]d, [ab]ort\n" );
+			}
+			break;
+
+		case 'v':	/* ldap protocol version */
+			getline( line, sizeof(line), stdin,
+			    "ldap version? " );
+			version = atoi( line );
+			if ( ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION,
+			    (void *) &version ) != 0 ) {
+				ldap_perror( ld, "ldap_set_option" );
+			}
+			break;
+
+		case 'b':	/* asynch bind */
+			getline( line, sizeof(line), stdin,
+			    "method 0->simple 3->sasl? " );
+			method = atoi( line );
+			if ( method == 0 ) {
+				method = LDAP_AUTH_SIMPLE;
+			} else if ( method == 3 ) {
+				method = LDAP_AUTH_SASL;
+			}
+			getline( dn, sizeof(dn), stdin, "dn? " );
+			strcat( dn, dnsuffix );
+
+			if ( method == LDAP_AUTH_SIMPLE && dn[0] != '\0' ) {
+			} else {
+				passwd[0] = '\0';
+			}
+
+			if ( method == LDAP_AUTH_SIMPLE ) {
+				if ( dn[0] != '\0' ) {
+					getline( passwd, sizeof(passwd), stdin,
+					    "password? " );
+				} else {
+					passwd[0] = '\0';
+				}
+				rc = ldap_simple_bind( ld, dn, passwd );
+			} else {
+				struct berval	cred;
+				char		mechanism[BUFSIZ];
+
+				getline( mechanism, sizeof(mechanism), stdin,
+				    "mechanism? " );
+				getline( passwd, sizeof(passwd), stdin,
+				    "credentials? " );
+				cred.bv_val = passwd;
+				cred.bv_len = strlen( passwd );
+				if ( ldap_sasl_bind( ld, dn, mechanism, &cred,
+				    NULL, NULL, &rc ) != LDAP_SUCCESS ) {
+					rc = -1;
+				}
+			}
+			if ( rc == -1 ) {
+				fprintf( stderr, "ldap_bind failed\n" );
+				ldap_perror( ld, "ldap_bind" );
+			} else {
+				printf( "Bind initiated\n" );
+				bound = 1;
+			}
+			break;
+
+		case 'B':	/* synch bind */
+			getline( line, sizeof(line), stdin,
+			    "method 0->simple 3->sasl? " );
+			method = atoi( line );
+			if ( method == 0 ) {
+				method = LDAP_AUTH_SIMPLE;
+			} else if ( method == 3 ) {
+				method = LDAP_AUTH_SASL;
+			}
+			getline( dn, sizeof(dn), stdin, "dn? " );
+			strcat( dn, dnsuffix );
+
+			if ( method == LDAP_AUTH_SIMPLE && dn[0] != '\0' ) {
+			} else {
+				passwd[0] = '\0';
+			}
+
+			if ( method == LDAP_AUTH_SIMPLE ) {
+				if ( dn[0] != '\0' ) {
+					getline( passwd, sizeof(passwd), stdin,
+					    "password? " );
+				} else {
+					passwd[0] = '\0';
+				}
+				rc = ldap_simple_bind_s( ld, dn, passwd );
+				fnname = "ldap_simple_bind_s";
+			} else {
+				struct berval	cred;
+				char		mechanism[BUFSIZ];
+
+				getline( mechanism, sizeof(mechanism), stdin,
+				    "mechanism? " );
+				getline( passwd, sizeof(passwd), stdin,
+				    "credentials? " );
+				cred.bv_val = passwd;
+				cred.bv_len = strlen( passwd );
+				rc = ldap_sasl_bind_s( ld, dn, mechanism,
+					&cred, NULL, NULL, NULL );
+				fnname = "ldap_sasl_bind_s";
+			}
+			if ( rc != LDAP_SUCCESS ) {
+				fprintf( stderr, "%s failed\n", fnname );
+				ldap_perror( ld, fnname );
+			} else {
+				printf( "Bind successful\n" );
+				bound = 1;
+			}
+			break;
+
+		case 'c':	/* compare */
+			getline( dn, sizeof(dn), stdin, "dn? " );
+			strcat( dn, dnsuffix );
+			getline( attr, sizeof(attr), stdin, "attr? " );
+			getline( value, sizeof(value), stdin, "value? " );
+
+			if ( (id = ldap_compare( ld, dn, attr, value )) == -1 )
+				ldap_perror( ld, "ldap_compare" );
+			else
+				printf( "Compare initiated with id %d\n", id );
+			break;
+
+		case 'x':	/* extended operation */
+			{
+			char		oid[100];
+			struct berval	val;
+
+			getline( oid, sizeof(oid), stdin, "oid? " );
+			getline( value, sizeof(value), stdin, "value? " );
+			if ( strncmp( value, "0x", 2 ) == 0 ) {
+				val.bv_val = (char *)malloc( strlen( value ) / 2 );
+				berval_from_hex( &val, value + 2 );
+			} else {
+				val.bv_val = strdup( value );
+				val.bv_len = strlen( value );
+			}
+			if ( ldap_extended_operation( ld, oid, &val, NULL,
+			    NULL, &id ) != LDAP_SUCCESS ) {
+				ldap_perror( ld, "ldap_extended_operation" );
+			} else {
+				printf( "Extended op initiated with id %d\n",
+				    id );
+			}
+			free( val.bv_val );
+			}
+			break;
+
+		case 'C':	/* set cache parameters */
+#ifdef NO_LIBLCACHE
+			getline( line, sizeof(line), stdin,
+			    "cache init (memcache 0)? " );
+#else
+			getline( line, sizeof(line), stdin,
+			    "cache init (memcache 0, lcache 1)? " );
+#endif
+			i = atoi( line );
+			if ( i == 0 ) {		/* memcache */
+				unsigned long	ttl, size;
+				char		**basedns, *dnarray[2];
+				LDAPMemCache	*mc;
+
+				getline( line, sizeof(line), stdin,
+				    "memcache ttl? " );
+				ttl = atoi( line );
+				getline( line, sizeof(line), stdin,
+				    "memcache size? " );
+				size = atoi( line );
+				getline( line, sizeof(line), stdin,
+				    "memcache baseDN? " );
+				if ( *line == '\0' ) {
+					basedns = NULL;
+				} else {
+					dnarray[0] = line;
+					dnarray[1] = NULL;
+					basedns = dnarray;
+				}
+				if (( rc = ldap_memcache_init( ttl, size,
+				    basedns, NULL, &mc )) != LDAP_SUCCESS ) {
+					fprintf( stderr,
+					    "ldap_memcache_init: %s\n",
+					    ldap_err2string( rc ));
+				} else if (( rc = ldap_memcache_set( ld, mc ))
+				    != LDAP_SUCCESS ) {
+					fprintf( stderr,
+					    "ldap_memcache_set: %s\n",
+					    ldap_err2string( rc ));
+				}
+
+#ifndef NO_LIBLCACHE
+			} else if ( i == 1 ) {
+				getline( line, sizeof(line), stdin,
+				    "cache config file? " );
+				if ( line[0] != '\0' ) {
+					if ( lcache_init( ld, line ) != 0 ) {
+						perror( "ldap_cache_init" );
+						break;
+					}
+				}
+				getline( line, sizeof(line), stdin,
+				    "cache on/off (on 1, off 0)? " );
+				if ( line[0] != '\0' ) {
+					i = atoi( line );
+					if ( ldap_set_option( ld,
+					    LDAP_OPT_CACHE_ENABLE, &i ) != 0 ) {
+						ldap_perror( ld, "ldap_cache_enable" );
+						break;
+					}
+				}
+				getline( line, sizeof(line), stdin,
+				  "cache strategy (check 0, populate 1, localdb 2)? " );
+				if ( line[0] != '\0' ) {
+					i = atoi( line );
+					if ( ldap_set_option( ld,
+					    LDAP_OPT_CACHE_STRATEGY, &i )
+					    != 0 ) {
+						ldap_perror(ld, "ldap_cache_strategy");
+						break;
+					}
+				}
+#endif /* !NO_LIBLCACHE */
+
+			} else {
+				fprintf( stderr, "unknown cachetype %d\n", i );
+			}
+			break;
+
+		case 'd':	/* turn on debugging */
+#ifndef _WIN32
+#ifdef LDAP_DEBUG
+			getline( line, sizeof(line), stdin, "debug level? " );
+			ldap_debug = atoi( line ) | LDAP_DEBUG_ANY;
+			if ( ldap_debug & LDAP_DEBUG_PACKETS ) {
+				ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL,
+					&ldap_debug );
+			}
+#else
+			printf( "Compile with -DLDAP_DEBUG for debugging\n" );
+#endif
+#endif
+			break;
+
+		case 'E':	/* explode a dn */
+			getline( line, sizeof(line), stdin, "dn? " );
+			exdn = ldap_explode_dn( line, 0 );
+			for ( i = 0; exdn != NULL && exdn[i] != NULL; i++ ) {
+				printf( "\t\"%s\"\n", exdn[i] );
+			}
+			break;
+
+		case 'R':	/* explode an rdn */
+			getline( line, sizeof(line), stdin, "rdn? " );
+			exdn = ldap_explode_rdn( line, 0 );
+			for ( i = 0; exdn != NULL && exdn[i] != NULL; i++ ) {
+				printf( "\t\"%s\"\n", exdn[i] );
+			}
+			break;
+
+		case 'm':	/* modify or modifyrdn */
+			if ( strncmp( line, "modify", 4 ) == 0 ) {
+				getline( dn, sizeof(dn), stdin, "dn? " );
+				strcat( dn, dnsuffix );
+				if ( (mods = get_modlist(
+				    "mod (0=>add, 1=>delete, 2=>replace -1=>done)? ",
+				    "attribute type? ", "attribute value? " ))
+				    == NULL )
+					break;
+				if ( (id = ldap_modify( ld, dn, mods )) == -1 )
+					ldap_perror( ld, "ldap_modify" );
+				else
+					printf( "Modify initiated with id %d\n",
+					    id );
+			} else if ( strncmp( line, "modrdn", 4 ) == 0 ) {
+				getline( dn, sizeof(dn), stdin, "dn? " );
+				strcat( dn, dnsuffix );
+				getline( rdn, sizeof(rdn), stdin, "newrdn? " );
+				getline( line, sizeof(line), stdin,
+				    "deleteoldrdn? " );
+				if ( (id = ldap_modrdn2( ld, dn, rdn,
+				    atoi(line) )) == -1 )
+					ldap_perror( ld, "ldap_modrdn" );
+				else
+					printf( "Modrdn initiated with id %d\n",
+					    id );
+			} else {
+				printf( "Possibilities: [modi]fy, [modr]dn\n" );
+			}
+			break;
+
+		case 'q':	/* quit */
+#ifdef CLDAP
+			if ( cldapflg )
+				cldap_close( ld );
+#endif /* CLDAP */
+			if ( !cldapflg )
+				ldap_unbind( ld );
+			exit( 0 );
+			break;
+
+		case 'r':	/* result or remove */
+			switch ( command3 ) {
+			case 's':	/* result */
+				getline( line, sizeof(line), stdin,
+				    "msgid (-1=>any)? " );
+				if ( line[0] == '\0' )
+					id = -1;
+				else
+					id = atoi( line );
+				getline( line, sizeof(line), stdin,
+				    "all (0=>any, 1=>all)? " );
+				if ( line[0] == '\0' )
+					all = 1;
+				else
+					all = atoi( line );
+				if (( msgtype = ldap_result( ld, id, all,
+				    tvp, &res )) < 1 ) {
+					ldap_perror( ld, "ldap_result" );
+					break;
+				}
+				printf( "\nresult: msgtype %d msgid %d\n",
+				    msgtype, ldap_msgid( res ) );
+				handle_result( ld, res, 0 );
+				res = NULL;
+				break;
+
+			case 'm':	/* remove */
+				getline( dn, sizeof(dn), stdin, "dn? " );
+				strcat( dn, dnsuffix );
+				if ( (id = ldap_delete( ld, dn )) == -1 )
+					ldap_perror( ld, "ldap_delete" );
+				else
+					printf( "Remove initiated with id %d\n",
+					    id );
+				break;
+
+			default:
+				printf( "Possibilities: [rem]ove, [res]ult\n" );
+				break;
+			}
+			break;
+
+		case 's':	/* search */
+			getline( dn, sizeof(dn), stdin, "searchbase? " );
+			strcat( dn, dnsuffix );
+			getline( line, sizeof(line), stdin,
+			    "scope (0=Base, 1=One Level, 2=Subtree)? " );
+			scope = atoi( line );
+			getline( filter, sizeof(filter), stdin,
+			    "search filter (e.g. sn=jones)? " );
+			types = get_list( "attrs to return? " );
+			getline( line, sizeof(line), stdin,
+			    "attrsonly (0=attrs&values, 1=attrs only)? " );
+			attrsonly = atoi( line );
+
+			if ( cldapflg ) {
+#ifdef CLDAP
+			    getline( line, sizeof(line), stdin,
+				"Requestor DN (for logging)? " );
+			    if ( cldap_search_s( ld, dn, scope, filter, types,
+				    attrsonly, &res, line ) != 0 ) {
+				ldap_perror( ld, "cldap_search_s" );
+			    } else {
+				printf( "\nresult: msgid %d\n",
+				    res->lm_msgid );
+				handle_result( ld, res, 0 );
+				res = NULL;
+			    }
+#endif /* CLDAP */
+			} else {
+			    if (( id = ldap_search( ld, dn, scope, filter,
+				    types, attrsonly  )) == -1 ) {
+				ldap_perror( ld, "ldap_search" );
+			    } else {
+				printf( "Search initiated with id %d\n", id );
+			    }
+			}
+			free_list( types );
+			break;
+
+		case 't':	/* set timeout value */
+			getline( line, sizeof(line), stdin, "timeout (-1=infinite)? " );
+			timeout.tv_sec = atoi( line );
+			if ( timeout.tv_sec < 0 ) {
+				tvp = NULL;
+			} else {
+				tvp = &timeout;
+			}
+			break;
+
+		case 'U':	/* set ufn search prefix */
+			getline( line, sizeof(line), stdin, "ufn prefix? " );
+			ldap_ufn_setprefix( ld, line );
+			break;
+
+		case 'u':	/* user friendly search w/optional timeout */
+			getline( dn, sizeof(dn), stdin, "ufn? " );
+			strcat( dn, dnsuffix );
+			types = get_list( "attrs to return? " );
+			getline( line, sizeof(line), stdin,
+			    "attrsonly (0=attrs&values, 1=attrs only)? " );
+			attrsonly = atoi( line );
+
+			if ( command2 == 't' ) {
+				id = ldap_ufn_search_c( ld, dn, types,
+				    attrsonly, &res, ldap_ufn_timeout,
+				    &timeout );
+			} else {
+				id = ldap_ufn_search_s( ld, dn, types,
+				    attrsonly, &res );
+			}
+			if ( res == NULL )
+				ldap_perror( ld, "ldap_ufn_search" );
+			else {
+				printf( "\nresult: err %d\n", id );
+				handle_result( ld, res, 0 );
+				res = NULL;
+			}
+			free_list( types );
+			break;
+
+		case 'l':	/* URL search */
+			getline( line, sizeof(line), stdin,
+			    "attrsonly (0=attrs&values, 1=attrs only)? " );
+			attrsonly = atoi( line );
+			getline( line, sizeof(line), stdin, "LDAP URL? " );
+			if (( id = ldap_url_search( ld, line, attrsonly  ))
+				== -1 ) {
+			    ldap_perror( ld, "ldap_url_search" );
+			} else {
+			    printf( "URL search initiated with id %d\n", id );
+			}
+			break;
+
+		case 'p':	/* parse LDAP URL */
+			getline( line, sizeof(line), stdin, "LDAP URL? " );
+			if (( i = ldap_url_parse( line, &ludp )) != 0 ) {
+			    fprintf( stderr, "ldap_url_parse: error %d (%s)\n", i,
+						url_parse_err2string( i ));
+			} else {
+			    printf( "\t  host: " );
+			    if ( ludp->lud_host == NULL ) {
+				printf( "DEFAULT\n" );
+			    } else {
+				printf( "<%s>\n", ludp->lud_host );
+			    }
+			    printf( "\t  port: " );
+			    if ( ludp->lud_port == 0 ) {
+				printf( "DEFAULT\n" );
+			    } else {
+				printf( "%d\n", ludp->lud_port );
+			    }
+			    printf( "\tsecure: %s\n", ( ludp->lud_options &
+				    LDAP_URL_OPT_SECURE ) != 0 ? "Yes" : "No" );
+			    printf( "\t    dn: " );
+			    if ( ludp->lud_dn == NULL ) {
+				printf( "ROOT\n" );
+			    } else {
+				printf( "%s\n", ludp->lud_dn );
+			    }
+			    printf( "\t attrs:" );
+			    if ( ludp->lud_attrs == NULL ) {
+				printf( " ALL" );
+			    } else {
+				for ( i = 0; ludp->lud_attrs[ i ] != NULL; ++i ) {
+				    printf( " <%s>", ludp->lud_attrs[ i ] );
+				}
+			    }
+			    printf( "\n\t scope: %s\n", ludp->lud_scope == LDAP_SCOPE_ONELEVEL ?
+				"ONE" : ludp->lud_scope == LDAP_SCOPE_BASE ? "BASE" :
+				ludp->lud_scope == LDAP_SCOPE_SUBTREE ? "SUB" : "**invalid**" );
+			    printf( "\tfilter: <%s>\n", ludp->lud_filter );
+			    ldap_free_urldesc( ludp );
+			}
+			    break;
+
+		case 'n':	/* set dn suffix, for convenience */
+			getline( line, sizeof(line), stdin, "DN suffix? " );
+			strcpy( dnsuffix, line );
+			break;
+
+		case 'N':	/* add an LDAPv3 control */
+			getline( line, sizeof(line), stdin,
+			    "Control oid (. to clear list)? " );
+			if ( *line == '.' && *(line+1) == '\0' ) {
+			    controls = NULL;
+			} else {
+			    newctrl = (LDAPControl *) malloc(
+				sizeof(LDAPControl) );
+			    newctrl->ldctl_oid = strdup( line );
+			    getline( line, sizeof(line), stdin,
+				"Control value? " );
+			    if ( strncmp( line, "0x", 2 ) == 0 ) {
+				    newctrl->ldctl_value.bv_val =
+				    (char *)malloc( strlen( line ) / 2 );
+				    berval_from_hex( &(newctrl->ldctl_value), 
+					    line + 2 );
+			    } else {
+				    newctrl->ldctl_value.bv_val
+					= strdup( line );
+			    }
+			    newctrl->ldctl_value.bv_len = strlen( line );
+			    getline( line, sizeof(line), stdin,
+				"Critical (0=no, 1=yes)? " );
+			    newctrl->ldctl_iscritical = atoi( line );
+			    add_control( &controls, newctrl );
+			}
+			ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS,
+			    controls );
+			ldap_get_option( ld, LDAP_OPT_SERVER_CONTROLS,
+			    &tmpctrls );
+			print_controls( tmpctrls, 0 );
+			break;
+
+		case 'P':	/* add a persistent search control */
+			getline( line, sizeof(line), stdin, "Changetypes to "
+			    " return (additive - add (1), delete (2), "
+			    "modify (4), modDN (8))? " );
+			changetypes = atoi(line);
+			getline( line, sizeof(line), stdin,
+			    "Return changes only (0=no, 1=yes)? " );
+			changesonly = atoi(line);
+			getline( line, sizeof(line), stdin, "Return entry "
+			    "change controls (0=no, 1=yes)? " );
+			return_echg_ctls = atoi(line);
+			getline( line, sizeof(line), stdin,
+				"Critical (0=no, 1=yes)? " );
+			if ( ldap_create_persistentsearch_control( ld,
+			    changetypes, changesonly, return_echg_ctls,
+			    (char)atoi(line), &newctrl ) != LDAP_SUCCESS ) {
+				ldap_perror( ld, "ldap_create_persistent"
+				    "search_control" );
+			} else {
+			    add_control( &controls, newctrl );
+			    ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS,
+				controls );
+			    ldap_get_option( ld, LDAP_OPT_SERVER_CONTROLS,
+				&tmpctrls );
+			    print_controls( tmpctrls, 0 );
+			}
+			break;
+			
+		case 'o':	/* set ldap options */
+			getline( line, sizeof(line), stdin, "alias deref (0=never, 1=searching, 2=finding, 3=always)?" );
+			i = atoi( line );
+			ldap_set_option( ld, LDAP_OPT_DEREF, &i );
+			getline( line, sizeof(line), stdin, "timelimit?" );
+			i = atoi( line );
+			ldap_set_option( ld, LDAP_OPT_TIMELIMIT, &i );
+			getline( line, sizeof(line), stdin, "sizelimit?" );
+			i = atoi( line );
+			ldap_set_option( ld, LDAP_OPT_SIZELIMIT, &i );
+
+#ifdef STR_TRANSLATION
+			getline( line, sizeof(line), stdin,
+				"Automatic translation of T.61 strings (0=no, 1=yes)?" );
+			if ( atoi( line ) == 0 ) {
+				ld->ld_lberoptions &= ~LBER_OPT_TRANSLATE_STRINGS;
+			} else {
+				ld->ld_lberoptions |= LBER_OPT_TRANSLATE_STRINGS;
+#ifdef LDAP_CHARSET_8859
+				getline( line, sizeof(line), stdin,
+					"Translate to/from ISO-8859 (0=no, 1=yes?" );
+				if ( atoi( line ) != 0 ) {
+					ldap_set_string_translators( ld,
+					    ldap_8859_to_t61,
+					    ldap_t61_to_8859 );
+				}
+#endif /* LDAP_CHARSET_8859 */
+			}
+#endif /* STR_TRANSLATION */
+
+#ifdef LDAP_DNS
+			getline( line, sizeof(line), stdin,
+				"Use DN & DNS to determine where to send requests (0=no, 1=yes)?" );
+			optval = ( atoi( line ) != 0 );
+			ldap_set_option( ld, LDAP_OPT_DNS, (void *) optval );
+#endif /* LDAP_DNS */
+
+			getline( line, sizeof(line), stdin,
+				"Recognize and chase referrals (0=no, 1=yes)?" );
+			optval = ( atoi( line ) != 0 );
+			ldap_set_option( ld, LDAP_OPT_REFERRALS,
+			    (void *) optval );
+			if ( optval ) {
+				getline( line, sizeof(line), stdin,
+					"Prompt for bind credentials when chasing referrals (0=no, 1=yes)?" );
+				if ( atoi( line ) != 0 ) {
+					ldap_set_rebind_proc( ld, bind_prompt,
+					    NULL );
+				}
+			}
+#ifdef NET_SSL
+			getline( line, sizeof(line), stdin,
+				"Use Secure Sockets Layer - SSL (0=no, 1=yes)?" );
+			optval = ( atoi( line ) != 0 );
+			if ( optval ) {
+				getline( line, sizeof(line), stdin,
+				    "security DB path?" ); 
+				if ( ldapssl_client_init( (*line == '\0') ?
+				    NULL : line, NULL ) < 0 ) {
+					perror( "ldapssl_client_init" );
+					optval = 0;     /* SSL not avail. */
+				} else if ( ldapssl_install_routines( ld )
+				    < 0 ) {
+					ldap_perror( ld,
+					    "ldapssl_install_routines" );
+					optval = 0;     /* SSL not avail. */
+				}
+			}
+
+			ldap_set_option( ld, LDAP_OPT_SSL,
+			    optval ? LDAP_OPT_ON : LDAP_OPT_OFF );
+
+			getline( line, sizeof(line), stdin,
+				"Set SSL options (0=no, 1=yes)?" );
+			optval = ( atoi( line ) != 0 );
+			while ( 1 ) {
+			    PRInt32 sslopt;
+			    PRBool  on;
+
+			    getline( line, sizeof(line), stdin,
+				    "Option to set (0 if done)?" );
+			    sslopt = atoi(line);
+			    if ( sslopt == 0 ) {
+				break;
+			    }
+			    getline( line, sizeof(line), stdin,
+				    "On=1, Off=0?" );
+			    on = ( atoi( line ) != 0 );
+			    if ( ldapssl_set_option( ld, sslopt, on ) != 0 ) {
+				ldap_perror( ld, "ldapssl_set_option" );
+			    }
+			}
+#endif
+
+			getline( line, sizeof(line), stdin, "Reconnect?" );
+			ldap_set_option( ld, LDAP_OPT_RECONNECT,
+			    ( atoi( line ) == 0 ) ? LDAP_OPT_OFF :
+			    LDAP_OPT_ON );
+
+			getline( line, sizeof(line), stdin, "Async I/O?" );
+			ldap_set_option( ld, LDAP_OPT_ASYNC_CONNECT,
+			    ( atoi( line ) == 0 ) ? LDAP_OPT_OFF :
+			    LDAP_OPT_ON );
+			break;
+
+		case 'I':	/* initialize display templates */
+			getline( line, sizeof(line), stdin,	
+				"Template file [ldaptemplates.conf]?" );
+			if (( i = ldap_init_templates( *line == '\0' ?
+				"ldaptemplates.conf" : line, &tmpllist ))
+				!= 0 ) {
+			    fprintf( stderr, "ldap_init_templates: %s\n",
+				    ldap_tmplerr2string( i ));
+			}
+			break;
+
+		case 'T':	/* read & display using template */
+			getline( dn, sizeof(dn), stdin, "entry DN? " );
+			strcat( dn, dnsuffix );
+			if (( i = ldap_entry2text_search( ld, dn, NULL, NULL,
+				tmpllist, NULL, NULL, entry2textwrite, stdout,
+				"\n", 0, 0 )) != LDAP_SUCCESS ) {
+			    fprintf( stderr, "ldap_entry2text_search: %s\n",
+				    ldap_err2string( i ));
+			}
+			break;
+
+		case 'L':	/* set preferred language */
+			getline( line, sizeof(line), stdin,
+				"Preferred language? " );
+			if ( *line == '\0' ) {
+				ldap_set_option( ld,
+				    LDAP_OPT_PREFERRED_LANGUAGE, NULL );
+			} else {
+				ldap_set_option( ld,
+				    LDAP_OPT_PREFERRED_LANGUAGE, line );
+			}
+			break;
+
+		case 'F':	/* create filter */
+			{
+				char	filtbuf[ 512 ], pattern[ 512 ];
+				char	prefix[ 512 ], suffix[ 512 ];
+				char	attr[ 512 ], value[ 512 ];
+				char	*dupvalue, **words;
+
+				getline( pattern, sizeof(pattern), stdin,
+				    "pattern? " );
+				getline( prefix, sizeof(prefix), stdin,
+				    "prefix? " );
+				getline( suffix, sizeof(suffix), stdin,
+				    "suffix? " );
+				getline( attr, sizeof(attr), stdin,
+				    "attribute? " );
+				getline( value, sizeof(value), stdin,
+				    "value? " );
+				
+				if (( dupvalue = strdup( value )) != NULL ) {
+					words = string2words( value, " " );
+				} else {
+					words = NULL;
+				}
+				if ( ldap_create_filter( filtbuf,
+				    sizeof(filtbuf), pattern, prefix, suffix,
+				    attr, value, words) != 0 ) {
+					fprintf( stderr,
+						"ldap_create_filter failed\n" );
+				} else {
+					printf( "filter is \"%s\"\n", filtbuf );
+				}
+				if ( dupvalue != NULL ) free( dupvalue );
+				if ( words != NULL ) free( words );
+			}
+			break;
+
+		case '?':	/* help */
+		case '\0':	/* help */
+    printf( "Commands: [ad]d         [ab]andon         [b]ind\n" );
+    printf( "          synch [B]ind  [c]ompare         [l]URL search\n" );
+    printf( "          [modi]fy      [modr]dn          [rem]ove\n" );
+    printf( "          [res]ult      [s]earch          [q]uit/unbind\n\n" );
+    printf( "          [u]fn search  [ut]fn search with timeout\n" );
+    printf( "          [d]ebug       [C]set cache parms[g]set msgid\n" );
+    printf( "          d[n]suffix    [t]imeout         [v]ersion\n" );
+    printf( "          [U]fn prefix  [?]help           [o]ptions\n" );
+    printf( "          [E]xplode dn  [p]arse LDAP URL  [R]explode RDN\n" );
+    printf( "          e[x]tended op [F]ilter create\n" );
+    printf( "          set co[N]trols    set preferred [L]anguage\n" );
+    printf( "          add a [P]ersistent search control\n" );
+    printf( "          [I]nitialize display templates\n" );
+    printf( "          [T]read entry and display using template\n" );
+			break;
+
+		default:
+			printf( "Invalid command.  Type ? for help.\n" );
+			break;
+		}
+
+		(void) memset( line, '\0', sizeof(line) );
+	}
+
+	return( 0 );
+}
+
+static void
+handle_result( LDAP *ld, LDAPMessage *lm, int onlyone )
+{
+	int	msgtype;
+
+	switch ( (msgtype = ldap_msgtype( lm )) ) {
+	case LDAP_RES_COMPARE:
+		printf( "Compare result\n" );
+		print_ldap_result( ld, lm, "compare" );
+		break;
+
+	case LDAP_RES_SEARCH_RESULT:
+		printf( "Search result\n" );
+		print_ldap_result( ld, lm, "search" );
+		break;
+
+	case LDAP_RES_SEARCH_ENTRY:
+		printf( "Search entry\n" );
+		print_search_entry( ld, lm, onlyone );
+		break;
+
+	case LDAP_RES_SEARCH_REFERENCE:
+		printf( "Search reference\n" );
+		print_search_reference( ld, lm, onlyone );
+		break;
+
+	case LDAP_RES_ADD:
+		printf( "Add result\n" );
+		print_ldap_result( ld, lm, "add" );
+		break;
+
+	case LDAP_RES_DELETE:
+		printf( "Delete result\n" );
+		print_ldap_result( ld, lm, "delete" );
+		break;
+
+	case LDAP_RES_MODIFY:
+		printf( "Modify result\n" );
+		print_ldap_result( ld, lm, "modify" );
+		break;
+
+	case LDAP_RES_MODRDN:
+		printf( "ModRDN result\n" );
+		print_ldap_result( ld, lm, "modrdn" );
+		break;
+
+	case LDAP_RES_BIND:
+		printf( "Bind result\n" );
+		print_ldap_result( ld, lm, "bind" );
+		break;
+	case LDAP_RES_EXTENDED:
+		if ( ldap_msgid( lm ) == LDAP_RES_UNSOLICITED ) {
+			printf( "Unsolicited result\n" );
+			print_ldap_result( ld, lm, "unsolicited" );
+		} else {
+			printf( "ExtendedOp result\n" );
+			print_ldap_result( ld, lm, "extendedop" );
+		}
+		break;
+
+	default:
+		printf( "Unknown result type 0x%x\n", msgtype );
+		print_ldap_result( ld, lm, "unknown" );
+	}
+
+	if ( !onlyone ) {
+		ldap_msgfree( lm );
+	}
+}
+
+static void
+print_ldap_result( LDAP *ld, LDAPMessage *lm, char *s )
+{
+	int		lderr;
+	char		*matcheddn, *errmsg, *oid, **refs;
+	LDAPControl	**ctrls;
+	struct berval	*servercred, *data;
+
+	if ( ldap_parse_result( ld, lm, &lderr, &matcheddn, &errmsg, &refs,
+	    &ctrls, 0 ) != LDAP_SUCCESS ) {
+		ldap_perror( ld, "ldap_parse_result" );
+	} else {
+		fprintf( stderr, "%s: %s", s, ldap_err2string( lderr ));
+		if ( lderr == LDAP_CONNECT_ERROR ) {
+			perror( " - " );
+		} else {
+			fputc( '\n', stderr );
+		}
+		if ( errmsg != NULL ) {
+			if ( *errmsg != '\0' ) {
+				fprintf( stderr, "Additional info: %s\n",
+				    errmsg );
+			}
+			ldap_memfree( errmsg );
+		}
+		if ( matcheddn != NULL ) {
+			if ( NAME_ERROR( lderr )) {
+				fprintf( stderr, "Matched DN: %s\n",
+				    matcheddn );
+			}
+			ldap_memfree( matcheddn );
+		}
+		print_referrals( refs, 1 );
+		print_controls( ctrls, 1 );
+	}
+
+	/* if SASL bind response, get and show server credentials */
+	if ( ldap_msgtype( lm ) == LDAP_RES_BIND &&
+	    ldap_parse_sasl_bind_result( ld, lm, &servercred, 0 ) ==
+	    LDAP_SUCCESS && servercred != NULL ) {
+		fputs( "\tSASL server credentials:\n", stderr );
+		bprint( servercred->bv_val, servercred->bv_len );
+		ber_bvfree( servercred );
+	}
+
+	/* if ExtendedOp response, get and show oid plus data */
+	if ( ldap_msgtype( lm ) == LDAP_RES_EXTENDED &&
+	    ldap_parse_extended_result( ld, lm, &oid, &data, 0 ) ==
+	    LDAP_SUCCESS ) {
+		if ( oid != NULL ) {
+			if ( strcmp ( oid, LDAP_NOTICE_OF_DISCONNECTION )
+			    == 0 ) {
+				printf(
+				    "\t%s Notice of Disconnection (OID: %s)\n",
+				    s, oid );
+			} else {
+				printf( "\t%s OID: %s\n", s, oid );
+			}
+			ldap_memfree( oid );
+		}
+		if ( data != NULL ) {
+			printf( "\t%s data:\n", s );
+			bprint( data->bv_val, data->bv_len );
+			ber_bvfree( data );
+		}
+	}
+}
+
+static void
+print_search_entry( LDAP *ld, LDAPMessage *res, int onlyone )
+{
+	BerElement	*ber;
+	char		*a, *dn, *ufn;
+	struct berval	**vals;
+	int		i, count;
+	LDAPMessage	*e, *msg;
+	LDAPControl	**ectrls;
+
+	count = 0;
+	for ( msg = ldap_first_message( ld, res );
+	    msg != NULL && ( !onlyone || count == 0 );
+	    msg = ldap_next_message( ld, msg ), ++count ) {
+		if ( ldap_msgtype( msg ) != LDAP_RES_SEARCH_ENTRY ) {
+		    handle_result( ld, msg, 1 );	/* something else */
+		    continue;
+		}
+		e = msg;
+
+		dn = ldap_get_dn( ld, e );
+		printf( "\tDN: %s\n", dn );
+
+		ufn = ldap_dn2ufn( dn );
+		printf( "\tUFN: %s\n", ufn );
+#ifdef WINSOCK
+		ldap_memfree( dn );
+		ldap_memfree( ufn );
+#else /* WINSOCK */
+		free( dn );
+		free( ufn );
+#endif /* WINSOCK */
+
+		for ( a = ldap_first_attribute( ld, e, &ber ); a != NULL;
+		    a = ldap_next_attribute( ld, e, ber ) ) {
+			printf( "\t\tATTR: %s\n", a );
+			if ( (vals = ldap_get_values_len( ld, e, a ))
+			    == NULL ) {
+				printf( "\t\t\t(no values)\n" );
+			} else {
+				for ( i = 0; vals[i] != NULL; i++ ) {
+					int		nonascii = 0;
+					unsigned long	j;
+
+					for ( j = 0; j < vals[i]->bv_len; j++ )
+						if ( !isascii( vals[i]->bv_val[j] ) ) {
+							nonascii = 1;
+							break;
+						}
+
+					if ( nonascii ) {
+						printf( "\t\t\tlength (%ld) (not ascii)\n", vals[i]->bv_len );
+#ifdef BPRINT_NONASCII
+						bprint( vals[i]->bv_val,
+						    vals[i]->bv_len );
+#endif /* BPRINT_NONASCII */
+						continue;
+					}
+					printf( "\t\t\tlength (%ld) %s\n",
+					    vals[i]->bv_len, vals[i]->bv_val );
+				}
+				ber_bvecfree( vals );
+			}
+			ldap_memfree( a );
+		}
+		if ( ldap_get_lderrno( ld, NULL, NULL ) != LDAP_SUCCESS ) {
+			ldap_perror( ld,
+			    "ldap_first_attribute/ldap_next_attribute" );
+		}
+		if ( ber != NULL ) {
+			ber_free( ber, 0 );
+		}
+
+		if ( ldap_get_entry_controls( ld, e, &ectrls )
+		    != LDAP_SUCCESS ) {
+			ldap_perror( ld, "ldap_get_entry_controls" );
+		} else {
+			int	changenumpresent;
+            ber_int_t changetype;
+			char	*prevdn;
+			ber_int_t  changenum;
+
+			if ( ldap_parse_entrychange_control( ld, ectrls,
+			    &changetype, &prevdn, &changenumpresent,
+			    &changenum ) == LDAP_SUCCESS ) {
+				fprintf( stderr, "EntryChangeNotification\n"
+				    "\tchangeType:   %s\n", 
+				    changetype_num2string( changetype ));
+				if ( prevdn != NULL ) {
+					fprintf( stderr,
+					    "\tpreviousDN:   \"%s\"\n",
+					    prevdn );
+				}
+				if ( changenumpresent ) {
+					fprintf( stderr, "\tchangeNumber: %d\n",
+					    changenum );
+				}
+				if ( prevdn != NULL ) {
+					free( prevdn );
+				}
+			}
+			print_controls( ectrls, 1 );
+		}
+	}
+}
+
+
+static char *
+changetype_num2string( ber_int_t chgtype )
+{
+    static char buf[ 25 ];
+    char	*s;
+
+    switch( chgtype ) {
+    case LDAP_CHANGETYPE_ADD:
+	s = "add";
+	break;
+    case LDAP_CHANGETYPE_DELETE:
+	s = "delete";
+	break;
+    case LDAP_CHANGETYPE_MODIFY:
+	s = "modify";
+	break;
+    case LDAP_CHANGETYPE_MODDN:
+	s = "moddn";
+	break;
+    default:
+	s = buf;
+	sprintf( s, "unknown (%d)", chgtype );
+    }
+
+    return( s );
+}
+
+
+static void
+print_search_reference( LDAP *ld, LDAPMessage *res, int onlyone )
+{
+	LDAPMessage	*msg;
+	LDAPControl	**ctrls;
+	char		**refs;
+	int		count;
+
+	count = 0;
+	for ( msg = ldap_first_message( ld, res );
+	    msg != NULL && ( !onlyone || count == 0 );
+	    msg = ldap_next_message( ld, msg ), ++count ) {
+		if ( ldap_msgtype( msg ) != LDAP_RES_SEARCH_REFERENCE ) {
+			handle_result( ld, msg, 1 );	/* something else */
+			continue;
+		}
+
+		if ( ldap_parse_reference( ld, msg, &refs, &ctrls, 0 ) !=
+		    LDAP_SUCCESS ) {
+			ldap_perror( ld, "ldap_parse_reference" );
+		} else {
+			print_referrals( refs, 1 );
+			print_controls( ctrls, 1 );
+		}
+	}
+}
+
+
+static void
+print_referrals( char **refs, int freeit )
+{
+	int	i;
+
+	if ( refs == NULL ) {
+		return;
+	}
+
+	fprintf( stderr, "Referrals:\n" );
+	for ( i = 0; refs[ i ] != NULL; ++i ) {
+		fprintf( stderr, "\t%s\n", refs[ i ] );
+	}
+
+	if ( freeit ) {
+		ldap_value_free( refs );
+	}
+}
+
+
+static void
+print_controls( LDAPControl **ctrls, int freeit )
+{
+	int	i;
+
+	if ( ctrls == NULL ) {
+		return;
+	}
+
+	fprintf( stderr, "Controls:\n" );
+	for ( i = 0; ctrls[ i ] != NULL; ++i ) {
+		if ( i > 0 ) {
+			fputs( "\t-----------\n", stderr );
+		}
+		fprintf( stderr, "\toid:      %s\n", ctrls[ i ]->ldctl_oid );
+		fprintf( stderr, "\tcritical: %s\n",
+		    ctrls[ i ]->ldctl_iscritical ? "YES" : "NO" );
+		fputs( "\tvalue:\n", stderr );
+		bprint( ctrls[ i ]->ldctl_value.bv_val,
+		    ctrls[ i ]->ldctl_value.bv_len );
+	}
+
+	if ( freeit ) {
+		ldap_controls_free( ctrls );
+	}
+}
+
+
+static int
+entry2textwrite( void *fp, char *buf, int len )
+{
+        return( fwrite( buf, len, 1, (FILE *)fp ) == 0 ? -1 : len );
+}
+
+
+/* similar to getfilter.c:break_into_words() */
+static char **
+string2words( char *str, char *delims )
+{
+    char        *word, **words;
+    int         count;
+    char        *lasts;
+
+    if (( words = (char **)calloc( 1, sizeof( char * ))) == NULL ) {
+	    return( NULL );
+    }
+    count = 0;
+    words[ count ] = NULL;
+
+    word = ldap_utf8strtok_r( str, delims, &lasts );
+    while ( word != NULL ) {
+        if (( words = (char **)realloc( words,
+                ( count + 2 ) * sizeof( char * ))) == NULL ) {
+	    free( words );
+            return( NULL );
+        }
+
+        words[ count ] = word;
+        words[ ++count ] = NULL;
+        word = ldap_utf8strtok_r( NULL, delims, &lasts );
+    }
+
+    return( words );
+}
+
+
+static const char *
+url_parse_err2string( int e )
+{
+    const char	*s = "unknown";
+
+    switch( e ) {
+    case LDAP_URL_ERR_NOTLDAP:
+	s = "URL doesn't begin with \"ldap://\"";
+	break;
+    case LDAP_URL_ERR_NODN:
+	s = "URL has no DN (required)";
+	break;
+    case LDAP_URL_ERR_BADSCOPE:
+	s = "URL scope string is invalid";
+	break;
+    case LDAP_URL_ERR_MEM:
+	s = "can't allocate memory space";
+	break;
+    case LDAP_URL_ERR_PARAM:
+	s = "bad parameter to an URL function";
+	break;
+    case LDAP_URL_UNRECOGNIZED_CRITICAL_EXTENSION:
+	s = "unrecognized critical URL extension";
+	break;
+    }
+
+    return( s );
+}
+
+
+/*
+ * Print arbitrary stuff, for debugging.
+ */
+
+#define BPLEN	48
+static void
+bprint( char *data, int len )
+{
+    static char	hexdig[] = "0123456789abcdef";
+    char	out[ BPLEN ];
+    int		i = 0;
+
+    memset( out, 0, BPLEN );
+    for ( ;; ) {
+	if ( len < 1 ) {
+		fprintf( stderr, "\t%s\n", ( i == 0 ) ? "(end)" : out );
+	    break;
+	}
+
+#ifndef HEX
+	if ( isgraph( (unsigned char)*data )) {
+	    out[ i ] = ' ';
+	    out[ i+1 ] = *data;
+	} else {
+#endif
+	    out[ i ] = hexdig[ ( *data & 0xf0 ) >> 4 ];
+	    out[ i+1 ] = hexdig[ *data & 0x0f ];
+#ifndef HEX
+	}
+#endif
+	i += 2;
+	len--;
+	data++;
+
+	if ( i > BPLEN - 2 ) {
+	    fprintf( stderr, "\t%s\n", out );
+	    memset( out, 0, BPLEN );
+	    i = 0;
+	    continue;
+	}
+	out[ i++ ] = ' ';
+    }
+
+    fflush( stderr );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/tmplout.c
@@ -0,0 +1,1144 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * tmplout.c:  display template library output routines for LDAP clients
+ * 
+ */
+
+#include "ldap-int.h"
+#include "disptmpl.h"
+
+#if defined(_WINDOWS) || defined(aix) || defined(SCOOS) || defined(OSF1) || defined(SOLARIS)
+#include <time.h> /* for struct tm and ctime */
+#endif
+
+
+/* This is totally lame, since it should be coming from time.h, but isn't. */
+#if defined(SOLARIS) 
+char *ctime_r(const time_t *, char *, int);
+#endif
+
+static int do_entry2text( LDAP *ld, char *buf, char *base, LDAPMessage *entry,
+	struct ldap_disptmpl *tmpl, char **defattrs, char ***defvals,
+	writeptype writeproc, void *writeparm, char *eol, int rdncount,
+	unsigned long opts, char *urlprefix );
+static int do_entry2text_search( LDAP *ld, char *dn, char *base,
+	LDAPMessage *entry, struct ldap_disptmpl *tmpllist, char **defattrs,
+	char ***defvals, writeptype writeproc, void *writeparm, char *eol,
+	int rdncount, unsigned long opts, char *urlprefix );
+static int do_vals2text( LDAP *ld, char *buf, char **vals, char *label,
+	int labelwidth, unsigned long syntaxid, writeptype writeproc,
+	void *writeparm, char *eol, int rdncount, char *urlprefix );
+static int max_label_len( struct ldap_disptmpl *tmpl );
+static int output_label( char *buf, char *label, int width,
+	writeptype writeproc, void *writeparm, char *eol, int html );
+static int output_dn( char *buf, char *dn, int width, int rdncount,
+	writeptype writeproc, void *writeparm, char *eol, char *urlprefix );
+static void strcat_escaped( char *s1, char *s2 );
+static char *time2text( char *ldtimestr, int dateonly );
+static long gtime( struct tm *tm );
+static int searchaction( LDAP *ld, char *buf, char *base, LDAPMessage *entry,
+	char *dn, struct ldap_tmplitem *tip, int labelwidth, int rdncount,
+	writeptype writeproc, void *writeparm, char *eol, char *urlprefix );
+
+#define DEF_LABEL_WIDTH		15
+#define SEARCH_TIMEOUT_SECS	120
+#define OCATTRNAME		"objectClass"
+
+
+#define NONFATAL_LDAP_ERR( err )	( err == LDAP_SUCCESS || \
+	err == LDAP_TIMELIMIT_EXCEEDED || err == LDAP_SIZELIMIT_EXCEEDED )
+
+#define DEF_LDAP_URL_PREFIX	"ldap:///"
+
+ 
+int
+LDAP_CALL
+ldap_entry2text(
+	LDAP			*ld,
+	char			*buf,		/* NULL for "use internal" */
+	LDAPMessage		*entry,
+	struct ldap_disptmpl	*tmpl,
+	char			**defattrs,
+	char			***defvals,
+	writeptype		writeproc,
+	void			*writeparm,
+	char			*eol,
+	int			rdncount,
+	unsigned long		opts
+)
+{
+    LDAPDebug( LDAP_DEBUG_TRACE, "ldap_entry2text\n", 0, 0, 0 );
+
+    return( do_entry2text( ld, buf, NULL, entry, tmpl, defattrs, defvals,
+		writeproc, writeparm, eol, rdncount, opts, NULL ));
+
+}
+
+
+
+int
+LDAP_CALL
+ldap_entry2html(
+	LDAP			*ld,
+	char			*buf,		/* NULL for "use internal" */
+	LDAPMessage		*entry,
+	struct ldap_disptmpl	*tmpl,
+	char			**defattrs,
+	char			***defvals,
+	writeptype		writeproc,
+	void			*writeparm,
+	char			*eol,
+	int			rdncount,
+	unsigned long		opts,
+	char			*base,
+	char			*urlprefix
+)
+{
+    LDAPDebug( LDAP_DEBUG_TRACE, "ldap_entry2html\n", 0, 0, 0 );
+
+    if ( urlprefix == NULL ) {
+	urlprefix = DEF_LDAP_URL_PREFIX;
+    }
+
+    return( do_entry2text( ld, buf, base, entry, tmpl, defattrs, defvals,
+		writeproc, writeparm, eol, rdncount, opts, urlprefix ));
+}
+
+
+static int
+do_entry2text(
+	LDAP			*ld,
+	char			*buf,		/* NULL for use-internal */
+	char			*base,		/* used for search actions */
+	LDAPMessage		*entry,
+	struct ldap_disptmpl	*tmpl,
+	char			**defattrs,
+	char			***defvals,
+	writeptype		writeproc,
+	void			*writeparm,
+	char			*eol,
+	int			rdncount,
+	unsigned long		opts,
+	char			*urlprefix	/* if non-NULL, do HTML */
+)
+{
+    int				i, err, html, show, labelwidth;
+    int				freebuf,  freevals;
+    char			*dn, **vals;
+    struct ldap_tmplitem	*rowp, *colp;
+
+    if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+	return( LDAP_PARAM_ERROR );
+    }
+
+    if ( writeproc == NULL ||
+	    !NSLDAPI_VALID_LDAPMESSAGE_ENTRY_POINTER( entry )) {
+	err = LDAP_PARAM_ERROR;
+	LDAP_SET_LDERRNO( ld, err, NULL, NULL );
+	return( err );
+    }
+
+    if (( dn = ldap_get_dn( ld, entry )) == NULL ) {
+	return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+    }
+
+    if ( buf == NULL ) {
+	if (( buf = NSLDAPI_MALLOC( LDAP_DTMPL_BUFSIZ )) == NULL ) {
+	    err = LDAP_NO_MEMORY;
+	    LDAP_SET_LDERRNO( ld, err, NULL, NULL );
+	    NSLDAPI_FREE( dn );
+	    return( err );
+	}
+	freebuf = 1;
+    } else {
+	freebuf = 0;
+    }
+
+    html = ( urlprefix != NULL );
+
+    if ( html ) {
+	/*
+	 * add HTML intro. and title
+	 */
+	if (!(( opts & LDAP_DISP_OPT_HTMLBODYONLY ) != 0 )) {
+	    sprintf( buf, "<HTML>%s<HEAD>%s<TITLE>%s%s - ", eol, eol, eol,
+		    ( tmpl == NULL ) ? "Entry" : tmpl->dt_name );
+	    (*writeproc)( writeparm, buf, strlen( buf ));
+	    output_dn( buf, dn, 0, rdncount, writeproc, writeparm, "", NULL );
+	    sprintf( buf, "%s</TITLE>%s</HEAD>%s<BODY>%s<H3>%s - ", eol, eol,
+		    eol, eol, ( tmpl == NULL ) ? "Entry" : tmpl->dt_name );
+	    (*writeproc)( writeparm, buf, strlen( buf ));
+	    output_dn( buf, dn, 0, rdncount, writeproc, writeparm, "", NULL );
+	    sprintf( buf, "</H3>%s", eol );
+	    (*writeproc)( writeparm, buf, strlen( buf ));
+	}
+
+	if (( opts & LDAP_DISP_OPT_NONLEAF ) != 0 &&
+		( vals = ldap_explode_dn( dn, 0 )) != NULL ) {
+	    char	*untagged;
+
+	    /*
+	     * add "Move Up" link
+	     */
+	    sprintf( buf, "<A HREF=\"%s", urlprefix );
+	    for ( i = 1; vals[ i ] != NULL; ++i ) {
+		if ( i > 1 ) {
+		     strcat_escaped( buf, ", " );
+		}
+		strcat_escaped( buf, vals[ i ] );
+	    }
+	    if ( vals[ 1 ] != NULL ) {
+		untagged = strchr( vals[ 1 ], '=' );
+	    } else {
+		untagged = "=The World";
+	    }
+	    sprintf( buf + strlen( buf ),
+		    "%s\">Move Up To <EM>%s</EM></A>%s<BR>",
+		    ( vals[ 1 ] == NULL ) ? "??one" : "",
+		    ( untagged != NULL ) ? untagged + 1 : vals[ 1 ], eol );
+	    (*writeproc)( writeparm, buf, strlen( buf ));
+
+	    /*
+	     * add "Browse" link
+	     */
+	    untagged = strchr( vals[ 0 ], '=' );
+	    sprintf( buf, "<A HREF=\"%s", urlprefix );
+	    strcat_escaped( buf, dn );
+	    sprintf( buf + strlen( buf ), "??one?(!(objectClass=dsa))\">Browse Below <EM>%s</EM></A>%s%s",
+		    ( untagged != NULL ) ? untagged + 1 : vals[ 0 ], eol, eol );
+	    (*writeproc)( writeparm, buf, strlen( buf ));
+
+	    ldap_value_free( vals );
+	}
+
+	(*writeproc)( writeparm, "<HR>", 4 );	/* horizontal rule */
+    } else {
+	(*writeproc)( writeparm, "\"", 1 );
+	output_dn( buf, dn, 0, rdncount, writeproc, writeparm, "", NULL );
+	sprintf( buf, "\"%s", eol );
+	(*writeproc)( writeparm, buf, strlen( buf ));
+    }
+
+    if ( tmpl != NULL && ( opts & LDAP_DISP_OPT_AUTOLABELWIDTH ) != 0 ) {
+	labelwidth = max_label_len( tmpl ) + 3;
+    } else {
+	labelwidth = DEF_LABEL_WIDTH;;
+    }
+
+    err = LDAP_SUCCESS;
+
+    if ( tmpl == NULL ) {
+	BerElement	*ber;
+	char		*attr;
+
+	ber = NULL;
+	for ( attr = ldap_first_attribute( ld, entry, &ber );
+		NONFATAL_LDAP_ERR( err ) && attr != NULL;
+		attr = ldap_next_attribute( ld, entry, ber )) {
+	    if (( vals = ldap_get_values( ld, entry, attr )) == NULL ) {
+		freevals = 0;
+		if ( defattrs != NULL ) {
+		    for ( i = 0; defattrs[ i ] != NULL; ++i ) {
+			if ( strcasecmp( attr, defattrs[ i ] ) == 0 ) {
+			    break;
+			}
+		    }
+		    if ( defattrs[ i ] != NULL ) {
+			vals = defvals[ i ];
+		    }
+		}
+	    } else {
+		freevals = 1;
+	    }
+
+	    if ( islower( *attr )) {	/* cosmetic -- upcase attr. name */
+		*attr = toupper( *attr );
+	    }
+
+	    err = do_vals2text( ld, buf, vals, attr, labelwidth,
+		    LDAP_SYN_CASEIGNORESTR, writeproc, writeparm, eol, 
+		    rdncount, urlprefix );
+	    if ( freevals ) {
+		ldap_value_free( vals );
+	    }
+	}
+	if ( ber == NULL ) {
+	    ber_free( ber, 0 );
+	}
+	/*
+	 * XXX check for errors in ldap_first_attribute/ldap_next_attribute
+	 * here (but what should we do if there was one?)
+	 */
+
+    } else {
+	for ( rowp = ldap_first_tmplrow( tmpl );
+		NONFATAL_LDAP_ERR( err ) && rowp != NULLTMPLITEM;
+		rowp = ldap_next_tmplrow( tmpl, rowp )) {
+	    for ( colp = ldap_first_tmplcol( tmpl, rowp ); colp != NULLTMPLITEM;
+		    colp = ldap_next_tmplcol( tmpl, rowp, colp )) {
+		vals = NULL;
+		if ( colp->ti_attrname == NULL || ( vals = ldap_get_values( ld,
+			entry, colp->ti_attrname )) == NULL ) {
+		    freevals = 0;
+		    if ( !LDAP_IS_TMPLITEM_OPTION_SET( colp,
+			    LDAP_DITEM_OPT_HIDEIFEMPTY ) && defattrs != NULL
+			    && colp->ti_attrname != NULL ) {
+			for ( i = 0; defattrs[ i ] != NULL; ++i ) {
+			    if ( strcasecmp( colp->ti_attrname, defattrs[ i ] )
+				    == 0 ) {
+				break;
+			    }
+			}
+			if ( defattrs[ i ] != NULL ) {
+			    vals = defvals[ i ];
+			}
+		    }
+		} else {
+		    freevals = 1;
+		    if ( LDAP_IS_TMPLITEM_OPTION_SET( colp,
+			    LDAP_DITEM_OPT_SORTVALUES ) && vals[ 0 ] != NULL
+			    && vals[ 1 ] != NULL ) {
+			ldap_sort_values(ld, vals, ldap_sort_strcasecmp);
+		    }
+		}
+
+		/*
+		 * don't bother even calling do_vals2text() if no values
+		 * or boolean with value false and "hide if false" option set
+		 */
+		show = ( vals != NULL && vals[ 0 ] != NULL );
+		if ( show && LDAP_GET_SYN_TYPE( colp->ti_syntaxid )
+			== LDAP_SYN_TYPE_BOOLEAN && LDAP_IS_TMPLITEM_OPTION_SET(
+			colp, LDAP_DITEM_OPT_HIDEIFFALSE ) &&
+			toupper( vals[ 0 ][ 0 ] ) != 'T' ) {
+		    show = 0;
+		}
+
+		if ( colp->ti_syntaxid == LDAP_SYN_SEARCHACTION ) {
+		    if (( opts & LDAP_DISP_OPT_DOSEARCHACTIONS ) != 0 ) {
+			if ( colp->ti_attrname == NULL || ( show &&
+				toupper( vals[ 0 ][ 0 ] ) == 'T' )) {
+			    err = searchaction( ld, buf, base, entry, dn, colp,
+				    labelwidth, rdncount, writeproc,
+				    writeparm, eol, urlprefix );
+			}
+		    }
+		    show = 0;
+		}
+
+		if ( show ) {
+		    err = do_vals2text( ld, buf, vals, colp->ti_label,
+			labelwidth, colp->ti_syntaxid, writeproc, writeparm,
+			eol, rdncount, urlprefix );
+		}
+
+		if ( freevals ) {
+		    ldap_value_free( vals );
+		}
+	    }
+	}
+    }
+
+    if ( html  && !(( opts & LDAP_DISP_OPT_HTMLBODYONLY ) != 0 )) {
+	sprintf( buf, "</BODY>%s</HTML>%s", eol, eol );
+	(*writeproc)( writeparm, buf, strlen( buf ));
+    }
+
+    NSLDAPI_FREE( dn );
+    if ( freebuf ) {
+	NSLDAPI_FREE( buf );
+    }
+
+    return( err );
+}
+
+	
+int
+LDAP_CALL
+ldap_entry2text_search(
+	LDAP			*ld,
+	char			*dn,		/* if NULL, use entry */
+	char			*base,		/* if NULL, no search actions */
+	LDAPMessage		*entry,		/* if NULL, use dn */
+	struct ldap_disptmpl*	tmpllist,	/* if NULL, load default file */
+	char			**defattrs,
+	char			***defvals,
+	writeptype		writeproc,
+	void			*writeparm,
+	char			*eol,
+	int			rdncount,	/* if 0, display full DN */
+	unsigned long		opts
+)
+{
+    LDAPDebug( LDAP_DEBUG_TRACE, "ldap_entry2text_search\n", 0, 0, 0 );
+
+    return( do_entry2text_search( ld, dn, base, entry, tmpllist, defattrs,
+	    defvals, writeproc, writeparm, eol, rdncount, opts, NULL ));
+}
+
+
+
+int
+LDAP_CALL
+ldap_entry2html_search(
+	LDAP			*ld,
+	char			*dn,		/* if NULL, use entry */
+	char			*base,		/* if NULL, no search actions */
+	LDAPMessage		*entry,		/* if NULL, use dn */
+	struct ldap_disptmpl*	tmpllist,	/* if NULL, load default file */
+	char			**defattrs,
+	char			***defvals,
+	writeptype		writeproc,
+	void			*writeparm,
+	char			*eol,
+	int			rdncount,	/* if 0, display full DN */
+	unsigned long		opts,
+	char			*urlprefix
+)
+{
+    LDAPDebug( LDAP_DEBUG_TRACE, "ldap_entry2html_search\n", 0, 0, 0 );
+
+    return( do_entry2text_search( ld, dn, base, entry, tmpllist, defattrs,
+	    defvals, writeproc, writeparm, eol, rdncount, opts, urlprefix ));
+}
+
+
+static int
+do_entry2text_search(
+	LDAP			*ld,
+	char			*dn,		/* if NULL, use entry */
+	char			*base,		/* if NULL, no search actions */
+	LDAPMessage		*entry,		/* if NULL, use dn */
+	struct ldap_disptmpl*	tmpllist,	/* if NULL, no template used */
+	char			**defattrs,
+	char			***defvals,
+	writeptype		writeproc,
+	void			*writeparm,
+	char			*eol,
+	int			rdncount,	/* if 0, display full DN */
+	unsigned long		opts,
+	char			*urlprefix
+)
+{
+    int				err, freedn, html;
+    char			*buf, **fetchattrs, **vals;
+    LDAPMessage			*ldmp;
+    struct ldap_disptmpl	*tmpl;
+    struct timeval		timeout;
+
+    if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+	return( LDAP_PARAM_ERROR );
+    }
+
+    if ( dn == NULL && entry == NULLMSG ) {
+	err = LDAP_PARAM_ERROR;
+	LDAP_SET_LDERRNO( ld, err, NULL, NULL );
+	return( err );
+    }
+
+    html = ( urlprefix != NULL );
+
+    timeout.tv_sec = SEARCH_TIMEOUT_SECS;
+    timeout.tv_usec = 0;
+
+    if (( buf = NSLDAPI_MALLOC( LDAP_DTMPL_BUFSIZ )) == NULL ) {
+	err = LDAP_NO_MEMORY;
+	LDAP_SET_LDERRNO( ld, err, NULL, NULL );
+	return( err );
+    }
+
+    freedn = 0;
+    tmpl = NULL;
+
+    if ( dn == NULL ) {
+	if (( dn = ldap_get_dn( ld, entry )) == NULL ) {
+	    NSLDAPI_FREE( buf );
+	    return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+	}
+	freedn = 1;
+    }
+
+
+    if ( tmpllist != NULL ) {
+	ldmp = NULLMSG;
+
+	if ( entry == NULL ) {
+	    char	*ocattrs[2];
+
+	    ocattrs[0] = OCATTRNAME;
+	    ocattrs[1] = NULL;
+#ifdef CLDAP
+	    if ( LDAP_IS_CLDAP( ld ))
+		    err = cldap_search_s( ld, dn, LDAP_SCOPE_BASE,
+			"objectClass=*", ocattrs, 0, &ldmp, NULL );
+	    else
+#endif /* CLDAP */
+		    err = ldap_search_st( ld, dn, LDAP_SCOPE_BASE,
+			    "objectClass=*", ocattrs, 0, &timeout, &ldmp );
+
+	    if ( err == LDAP_SUCCESS ) {
+		entry = ldap_first_entry( ld, ldmp );
+	    }
+	}
+
+	if ( entry != NULL ) {
+	    vals = ldap_get_values( ld, entry, OCATTRNAME );
+	    tmpl = ldap_oc2template( vals, tmpllist );
+	    if ( vals != NULL ) {
+		ldap_value_free( vals );
+	    }
+	}
+	if ( ldmp != NULL ) {
+	    ldap_msgfree( ldmp );
+	}
+    }
+
+    entry = NULL;
+
+    if ( tmpl == NULL ) {
+	fetchattrs = NULL;
+    } else {
+	fetchattrs = ldap_tmplattrs( tmpl, NULL, 1, LDAP_SYN_OPT_DEFER );
+    }
+
+#ifdef CLDAP
+    if ( LDAP_IS_CLDAP( ld ))
+	err = cldap_search_s( ld, dn, LDAP_SCOPE_BASE, "objectClass=*",
+		fetchattrs, 0, &ldmp, NULL );
+    else
+#endif /* CLDAP */
+	err = ldap_search_st( ld, dn, LDAP_SCOPE_BASE, "objectClass=*",
+		fetchattrs, 0, &timeout, &ldmp );
+
+    if ( freedn ) {
+	NSLDAPI_FREE( dn );
+    }
+    if ( fetchattrs != NULL ) {
+	ldap_value_free( fetchattrs );
+    }
+
+    if ( err != LDAP_SUCCESS ||
+	    ( entry = ldap_first_entry( ld, ldmp )) == NULL ) {
+	NSLDAPI_FREE( buf );
+	return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+    }
+
+    err = do_entry2text( ld, buf, base, entry, tmpl, defattrs, defvals,
+	    writeproc, writeparm, eol, rdncount, opts, urlprefix );
+
+    NSLDAPI_FREE( buf );
+    ldap_msgfree( ldmp );
+    return( err );
+}
+	    
+
+int
+LDAP_CALL
+ldap_vals2text(
+	LDAP			*ld,
+	char			*buf,		/* NULL for "use internal" */
+	char			**vals,
+	char			*label,
+	int			labelwidth,	/* 0 means use default */
+	unsigned long		syntaxid,
+	writeptype		writeproc,
+	void			*writeparm,
+	char			*eol,
+	int			rdncount
+)
+{
+    LDAPDebug( LDAP_DEBUG_TRACE, "ldap_vals2text\n", 0, 0, 0 );
+
+    return( do_vals2text( ld, buf, vals, label, labelwidth, syntaxid,
+		writeproc, writeparm, eol, rdncount, NULL ));
+}
+
+
+int
+LDAP_CALL
+ldap_vals2html(
+	LDAP			*ld,
+	char			*buf,		/* NULL for "use internal" */
+	char			**vals,
+	char			*label,
+	int			labelwidth,	/* 0 means use default */
+	unsigned long		syntaxid,
+	writeptype		writeproc,
+	void			*writeparm,
+	char			*eol,
+	int			rdncount,
+	char			*urlprefix
+)
+{
+    LDAPDebug( LDAP_DEBUG_TRACE, "ldap_vals2html\n", 0, 0, 0 );
+
+    if ( urlprefix == NULL ) {
+	urlprefix = DEF_LDAP_URL_PREFIX;
+    }
+
+    return( do_vals2text( ld, buf, vals, label, labelwidth, syntaxid,
+		writeproc, writeparm, eol, rdncount, urlprefix ));
+}
+
+
+static int
+do_vals2text(
+	LDAP			*ld,
+	char			*buf,		/* NULL for "use internal" */
+	char			**vals,
+	char			*label,
+	int			labelwidth,	/* 0 means use default */
+	unsigned long		syntaxid,
+	writeptype		writeproc,
+	void			*writeparm,
+	char			*eol,
+	int			rdncount,
+	char			*urlprefix
+)
+{
+    int		err, i, html, writeoutval, freebuf, notascii;
+    char	*p, *s, *outval;
+
+    if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) || writeproc == NULL ) {
+	return( LDAP_PARAM_ERROR );
+    }
+
+    if ( vals == NULL ) {
+	return( LDAP_SUCCESS );
+    }
+
+    html = ( urlprefix != NULL );
+
+    switch( LDAP_GET_SYN_TYPE( syntaxid )) {
+    case LDAP_SYN_TYPE_TEXT:
+    case LDAP_SYN_TYPE_BOOLEAN:
+	break;		/* we only bother with these two types... */
+    default:
+	return( LDAP_SUCCESS );
+    }
+
+    if ( labelwidth == 0 || labelwidth < 0 ) {
+	labelwidth = DEF_LABEL_WIDTH;
+    }
+
+    if ( buf == NULL ) {
+	if (( buf = NSLDAPI_MALLOC( LDAP_DTMPL_BUFSIZ )) == NULL ) {
+	    err = LDAP_NO_MEMORY;
+	    LDAP_SET_LDERRNO( ld, err, NULL, NULL );
+	    return( err );
+	}
+	freebuf = 1;
+    } else {
+	freebuf = 0;
+    }
+
+    output_label( buf, label, labelwidth, writeproc, writeparm, eol, html );
+
+    for ( i = 0; vals[ i ] != NULL; ++i ) {
+	for ( p = vals[ i ]; *p != '\0'; ++p ) {
+	    if ( !isascii( *p )) {
+		break;
+	    }
+	}
+	notascii = ( *p != '\0' );
+	outval = notascii ? "(unable to display non-ASCII text value)"
+		: vals[ i ];
+
+	writeoutval = 0;	/* if non-zero, write outval after switch */
+
+	switch( syntaxid ) {
+	case LDAP_SYN_CASEIGNORESTR:
+	    ++writeoutval;
+	    break;
+
+	case LDAP_SYN_RFC822ADDR:
+	    if ( html ) {
+		strcpy( buf, "<DD><A HREF=\"mailto:" );
+		strcat_escaped( buf, outval );
+		sprintf( buf + strlen( buf ), "\">%s</A><BR>%s", outval, eol );
+		(*writeproc)( writeparm, buf, strlen( buf ));
+	    } else {
+		++writeoutval;
+	    }
+	    break;
+
+	case LDAP_SYN_DN:	/* for now */
+	    output_dn( buf, outval, labelwidth, rdncount, writeproc,
+		    writeparm, eol, urlprefix );
+	    break;
+
+	case LDAP_SYN_MULTILINESTR:
+	    if ( i > 0 && !html ) {
+		output_label( buf, label, labelwidth, writeproc,
+			writeparm, eol, html );
+	    }
+
+	    p = s = outval;
+	    while (( s = strchr( s, '$' )) != NULL ) {
+		*s++ = '\0';
+		while ( ldap_utf8isspace( s )) {
+		    ++s;
+		}
+		if ( html ) {
+		    sprintf( buf, "<DD>%s<BR>%s", p, eol );
+		} else {
+		    sprintf( buf, "%-*s%s%s", labelwidth, " ", p, eol );
+		}
+		(*writeproc)( writeparm, buf, strlen( buf ));
+		p = s;
+	    }
+	    outval = p;
+	    ++writeoutval;
+	    break;
+
+	case LDAP_SYN_BOOLEAN:
+	    outval = toupper( outval[ 0 ] ) == 'T' ? "TRUE" : "FALSE";
+	    ++writeoutval;
+	    break;
+
+	case LDAP_SYN_TIME:
+	case LDAP_SYN_DATE:
+	    outval = time2text( outval, syntaxid == LDAP_SYN_DATE );
+	    ++writeoutval;
+	    break;
+
+	case LDAP_SYN_LABELEDURL:
+	    if ( !notascii && ( p = strchr( outval, '$' )) != NULL ) {
+		*p++ = '\0';
+		while ( ldap_utf8isspace( p )) {
+		    ++p;
+		}
+		s = outval;
+	    } else if ( !notascii && ( s = strchr( outval, ' ' )) != NULL ) {
+		*s++ = '\0';
+		while ( ldap_utf8isspace( s )) {
+		    ++s;
+		}
+		p = outval;
+	    } else {
+		s = "URL";
+		p = outval;
+	    }
+
+	    /*
+	     * at this point `s' points to the label & `p' to the URL
+	     */
+	    if ( html ) {
+		sprintf( buf, "<DD><A HREF=\"%s\">%s</A><BR>%s", p, s, eol );
+	    } else {
+		sprintf( buf, "%-*s%s%s%-*s%s%s", labelwidth, " ",
+		    s, eol, labelwidth + 2, " ",p , eol );
+	    }
+	    (*writeproc)( writeparm, buf, strlen( buf ));
+	    break;
+
+	default:
+	    sprintf( buf, " Can't display item type %ld%s",
+		    syntaxid, eol );
+	    (*writeproc)( writeparm, buf, strlen( buf ));
+	}
+
+	if ( writeoutval ) {
+	    if ( html ) {
+		sprintf( buf, "<DD>%s<BR>%s", outval, eol );
+	    } else {
+		sprintf( buf, "%-*s%s%s", labelwidth, " ", outval, eol );
+	    }
+	    (*writeproc)( writeparm, buf, strlen( buf ));
+	}
+    }
+
+    if ( freebuf ) {
+	NSLDAPI_FREE( buf );
+    }
+
+    return( LDAP_SUCCESS );
+}
+
+
+static int
+max_label_len( struct ldap_disptmpl *tmpl )
+{
+    struct ldap_tmplitem	*rowp, *colp;
+    int				len, maxlen;
+
+    maxlen = 0;
+
+    for ( rowp = ldap_first_tmplrow( tmpl ); rowp != NULLTMPLITEM;
+	    rowp = ldap_next_tmplrow( tmpl, rowp )) {
+	for ( colp = ldap_first_tmplcol( tmpl, rowp ); colp != NULLTMPLITEM;
+		colp = ldap_next_tmplcol( tmpl, rowp, colp )) {
+	    if (( len = strlen( colp->ti_label )) > maxlen ) {
+		maxlen = len;
+	    }
+	}
+    }
+
+    return( maxlen );
+}
+
+
+static int
+output_label( char *buf, char *label, int width, writeptype writeproc,
+	void *writeparm, char *eol, int html )
+{
+    char	*p;
+
+    if ( html ) {
+	sprintf( buf, "<DT><B>%s</B>", label );
+    } else {
+	auto size_t w;
+	sprintf( buf, " %s:", label );
+	p = buf + strlen( buf );
+
+	for (w = ldap_utf8characters(buf); w < (size_t)width; ++w) {
+	    *p++ = ' ';
+	}
+
+	*p = '\0';
+	strcat( buf, eol );
+    }
+
+    return ((*writeproc)( writeparm, buf, strlen( buf )));
+}
+
+
+static int
+output_dn( char *buf, char *dn, int width, int rdncount,
+	writeptype writeproc, void *writeparm, char *eol, char *urlprefix )
+{
+    char	**dnrdns;
+    int		i;
+
+    if (( dnrdns = ldap_explode_dn( dn, 1 )) == NULL ) {
+	return( -1 );
+    }
+
+    if ( urlprefix != NULL ) {
+	sprintf( buf, "<DD><A HREF=\"%s", urlprefix );
+	strcat_escaped( buf, dn );
+	strcat( buf, "\">" );
+    } else if ( width > 0 ) {
+	sprintf( buf, "%-*s", width, " " );
+    } else {
+	*buf = '\0';
+    }
+
+    for ( i = 0; dnrdns[ i ] != NULL && ( rdncount == 0 || i < rdncount );
+	    ++i ) {
+	if ( i > 0 ) {
+	    strcat( buf, ", " );
+	}
+	strcat( buf, dnrdns[ i ] );
+    }
+
+    if ( urlprefix != NULL ) {
+	strcat( buf, "</A><BR>" );
+    }
+
+    ldap_value_free( dnrdns );
+
+    strcat( buf, eol );
+
+    return ((*writeproc)( writeparm, buf, strlen( buf )));
+}
+
+
+
+#define HREF_CHAR_ACCEPTABLE( c )	(( c >= '-' && c <= '9' ) ||	\
+					 ( c >= '@' && c <= 'Z' ) ||	\
+					 ( c == '_' ) ||		\
+					 ( c >= 'a' && c <= 'z' ))
+
+static void
+strcat_escaped( char *s1, char *s2 )
+{
+    char	*p, *q;
+    char	*hexdig = "0123456789ABCDEF";
+
+    p = s1 + strlen( s1 );
+    for ( q = s2; *q != '\0'; ++q ) {
+	if ( HREF_CHAR_ACCEPTABLE( *q )) {
+	    *p++ = *q;
+	} else {
+	    *p++ = '%';
+	    *p++ = hexdig[ 0x0F & ((*(unsigned char*)q) >> 4) ];
+	    *p++ = hexdig[ 0x0F & *q ];
+	}
+    }
+
+    *p = '\0';
+}
+
+
+#define GET2BYTENUM( p )	(( *p - '0' ) * 10 + ( *(p+1) - '0' ))
+
+static char *
+time2text( char *ldtimestr, int dateonly )
+{
+    int			len;
+    struct tm		t;
+    char		*p, *timestr, zone, *fmterr = "badly formatted time";
+    time_t		gmttime;
+/* CTIME for this platform doesn't use this. */
+#if !defined(SUNOS4) && !defined(BSDI) && !defined(LINUX1_2) && \
+    !defined(SNI) && !defined(_WIN32) && !defined(macintosh) && !defined(LINUX)
+    char		buf[26];
+#endif
+
+    memset( (char *)&t, 0, sizeof( struct tm ));
+    if (( len = (int)strlen( ldtimestr )) < 13 ) {
+	return( fmterr );
+    }
+    if ( len > 15 ) {   /* throw away excess from 4-digit year time string */
+	len = 15;
+    } else if ( len == 14 ) {
+	len = 13;       /* assume we have a time w/2-digit year (len=13) */
+    }
+
+    for ( p = ldtimestr; p - ldtimestr + 1 < len; ++p ) {
+	if ( !isdigit( *p )) {
+	    return( fmterr );
+	}
+    }
+
+    p = ldtimestr;
+    t.tm_year = GET2BYTENUM( p ); p += 2;
+    if ( len == 15 ) {
+	t.tm_year = 100 * (t.tm_year - 19);
+	t.tm_year += GET2BYTENUM( p ); p += 2;
+    }
+    else {
+	/* 2 digit years...assumed to be in the range (19)70 through
+	   (20)69 ...less than 70 (for now, 38) means 20xx */
+	if(t.tm_year < 70) {
+	    t.tm_year += 100;
+	}
+    }
+    t.tm_mon = GET2BYTENUM( p ) - 1; p += 2;
+    t.tm_mday = GET2BYTENUM( p ); p += 2;
+    t.tm_hour = GET2BYTENUM( p ); p += 2;
+    t.tm_min = GET2BYTENUM( p ); p += 2;
+    t.tm_sec = GET2BYTENUM( p ); p += 2;
+
+    if (( zone = *p ) == 'Z' ) {	/* GMT */
+	zone = '\0';	/* no need to indicate on screen, so we make it null */
+    }
+
+    gmttime = gtime( &t );
+    timestr = NSLDAPI_CTIME( &gmttime, buf, sizeof(buf) );
+
+    timestr[ strlen( timestr ) - 1 ] = zone;	/* replace trailing newline */
+    if ( dateonly ) {
+	strcpy( timestr + 11, timestr + 20 );
+    }
+
+    return( timestr );
+}
+
+
+
+/* gtime.c - inverse gmtime */
+
+#if !defined( macintosh ) && !defined( _WINDOWS ) && !defined( DOS ) && !defined(XP_OS2)
+#include <sys/time.h>
+#endif /* !macintosh */
+
+/* gtime(): the inverse of localtime().
+	This routine was supplied by Mike Accetta at CMU many years ago.
+ */
+
+static int	dmsize[] = {
+    31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+#define	dysize(y)	\
+	(((y) % 4) ? 365 : (((y) % 100) ? 366 : (((y) % 400) ? 365 : 366)))
+
+/*
+#define	YEAR(y)		((y) >= 100 ? (y) : (y) + 1900)
+*/
+#define YEAR(y)		(((y) < 1900) ? ((y) + 1900) : (y)) 
+
+/*  */
+
+static long	gtime ( struct tm *tm )
+{
+    register int    i,
+                    sec,
+                    mins,
+                    hour,
+                    mday,
+                    mon,
+                    year;
+    register long   result;
+
+    if ((sec = tm -> tm_sec) < 0 || sec > 59
+	    || (mins = tm -> tm_min) < 0 || mins > 59
+	    || (hour = tm -> tm_hour) < 0 || hour > 24
+	    || (mday = tm -> tm_mday) < 1 || mday > 31
+	    || (mon = tm -> tm_mon + 1) < 1 || mon > 12)
+	return ((long) -1);
+    if (hour == 24) {
+	hour = 0;
+	mday++;
+    }
+    year = YEAR (tm -> tm_year);
+
+    result = 0L;
+    for (i = 1970; i < year; i++)
+	result += dysize (i);
+    if (dysize (year) == 366 && mon >= 3)
+	result++;
+    while (--mon)
+	result += dmsize[mon - 1];
+    result += mday - 1;
+    result = 24 * result + hour;
+    result = 60 * result + mins;
+    result = 60 * result + sec;
+
+    return result;
+}
+
+static int
+searchaction( LDAP *ld, char *buf, char *base, LDAPMessage *entry, char *dn,
+	struct ldap_tmplitem *tip, int labelwidth, int rdncount,
+	writeptype writeproc, void *writeparm, char *eol, char *urlprefix )
+{
+    int			err = LDAP_SUCCESS, lderr, i, count, html;
+    char		**vals, **members;
+    char		*value, *filtpattern, *attr, *selectname;
+    char		*retattrs[2], filter[ 256 ];
+    LDAPMessage		*ldmp;
+    struct timeval	timeout;
+
+    html = ( urlprefix != NULL );
+
+    for ( i = 0; tip->ti_args != NULL && tip->ti_args[ i ] != NULL; ++i ) {
+	;
+    }
+    if ( i < 3 ) {
+	return( LDAP_PARAM_ERROR );
+    }
+    attr = tip->ti_args[ 0 ];
+    filtpattern = tip->ti_args[ 1 ];
+    retattrs[ 0 ] = tip->ti_args[ 2 ];
+    retattrs[ 1 ] = NULL;
+    selectname = tip->ti_args[ 3 ];
+
+    vals = NULL;
+    if ( attr == NULL ) {
+	value = NULL;
+    } else if ( strcasecmp( attr, "-dnb" ) == 0 ) {
+	return( LDAP_PARAM_ERROR );
+    } else if ( strcasecmp( attr, "-dnt" ) == 0 ) {
+	value = dn;
+    } else if (( vals = ldap_get_values( ld, entry, attr )) != NULL ) {
+	value = vals[ 0 ];
+    } else {
+	value = NULL;
+    }
+
+    ldap_build_filter( filter, sizeof( filter ), filtpattern, NULL, NULL, NULL,
+	    value, NULL );
+
+    if ( html ) {
+	/*
+	 * if we are generating HTML, we add an HREF link that embodies this
+	 * search action as an LDAP URL, instead of actually doing the search
+	 * now.
+	 */
+	sprintf( buf, "<DT><A HREF=\"%s", urlprefix );
+	if ( base != NULL ) {
+	    strcat_escaped( buf, base );
+	}
+	strcat( buf, "??sub?" );
+	strcat_escaped( buf, filter );
+	sprintf( buf + strlen( buf ), "\"><B>%s</B></A><DD><BR>%s",
+		tip->ti_label, eol );
+	if ((*writeproc)( writeparm, buf, strlen( buf )) < 0 ) {
+	    return( LDAP_LOCAL_ERROR );
+	}
+	return( LDAP_SUCCESS );
+    }
+
+    timeout.tv_sec = SEARCH_TIMEOUT_SECS;
+    timeout.tv_usec = 0;
+
+#ifdef CLDAP
+    if ( LDAP_IS_CLDAP( ld ))
+	lderr = cldap_search_s( ld, base, LDAP_SCOPE_SUBTREE, filter, retattrs,
+		0, &ldmp, NULL );
+    else
+#endif /* CLDAP */
+	lderr = ldap_search_st( ld, base, LDAP_SCOPE_SUBTREE, filter,
+		retattrs, 0, &timeout, &ldmp );
+
+    if ( lderr == LDAP_SUCCESS || NONFATAL_LDAP_ERR( lderr )) {
+	if (( count = ldap_count_entries( ld, ldmp )) > 0 ) {
+	    if (( members = (char **)NSLDAPI_MALLOC( (count + 1)
+		    * sizeof(char *))) == NULL ) {
+		err = LDAP_NO_MEMORY;
+	    } else {
+		for ( i = 0, entry = ldap_first_entry( ld, ldmp );
+			entry != NULL;
+			entry = ldap_next_entry( ld, entry ), ++i ) {
+		    members[ i ] = ldap_get_dn( ld, entry );
+		}
+		members[ i ] = NULL;
+
+		ldap_sort_values(ld,members, ldap_sort_strcasecmp);
+
+		err = do_vals2text( ld, NULL, members, tip->ti_label,
+			html ? -1 : 0, LDAP_SYN_DN, writeproc, writeparm,
+			eol, rdncount, urlprefix );
+
+		ldap_value_free( members );
+	    }
+	}
+	ldap_msgfree( ldmp );
+    }
+
+    
+    if ( vals != NULL ) {
+	ldap_value_free( vals );
+    }
+
+    return(( err == LDAP_SUCCESS ) ? lderr : err );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/tmpltest.c
@@ -0,0 +1,319 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+/* tmpltest.c - implements a test/config templates. */
+#include <stdio.h>
+#include <sys/types.h>
+
+#ifdef _WINDOWS
+#include <windows.h>
+#endif
+
+#include "ldap-int.h"
+#include "disptmpl.h"
+#include "srchpref.h"
+
+#ifdef MACOS
+#include <stdlib.h>
+#include <console.h>
+#endif /* MACOS */
+
+#ifdef NEEDPROTOS
+void dump_tmpl( struct ldap_disptmpl *tmpl );
+void dump_srchpref( struct ldap_searchobj *sp );
+#else /* NEEDPROTOS */
+void dump_tmpl();
+void dump_srchpref();
+#endif /* NEEDPROTOS */
+
+
+#define NULLSTRINGIFNULL( s )	( s == NULL ? "(null)" : s )
+
+
+int
+main( int argc, char **argv )
+{
+    struct ldap_disptmpl	*templates, *dtp;
+    struct ldap_searchobj	*so, *sop;
+    int				err;
+
+#ifdef MACOS
+	ccommand( &argv );
+	for ( argc = 0; argv[ argc ] != NULL; ++argc ) {
+	    ;
+	}
+	cshow( stdout );
+#endif /* MACOS */
+
+    if (( err = ldap_init_templates( "ldaptemplates.conf", &templates ))
+	    != 0 ) {
+	fprintf( stderr, "ldap_init_templates failed (%d)\n", err );
+	exit( 1 );
+    }
+
+    if (( err = ldap_init_searchprefs( "ldapsearchprefs.conf", &so ))
+	    != 0 ) {
+	fprintf( stderr, "ldap_init_searchprefs failed (%d)\n", err );
+	exit( 1 );
+    }
+
+    if ( argc == 1 ) {
+	printf( "*** Display Templates:\n" );
+	for ( dtp = ldap_first_disptmpl( templates ); dtp != NULLDISPTMPL;
+		dtp = ldap_next_disptmpl( templates, dtp )) {
+	    dump_tmpl( dtp );
+	    printf( "\n\n" );
+	}
+
+	printf( "\n\n*** Search Objects:\n" );
+	for ( sop = ldap_first_searchobj( so ); sop != NULLSEARCHOBJ;
+		    sop = ldap_next_searchobj( so, sop )) {
+	    dump_srchpref( sop );
+	    printf( "\n\n" );
+	}
+
+    } else {
+	if (( dtp = ldap_oc2template( ++argv, templates )) == NULL ) {
+	    fprintf( stderr, "no matching template found\n" );
+	} else {
+	    dump_tmpl( dtp );
+	}
+    }
+
+
+    ldap_free_templates( templates );
+    ldap_free_searchprefs( so );
+
+    exit( 0 );
+}
+
+
+static char *syn_name[] = {
+    "?", "CIS", "MLS", "DN", "BOOL", "JPEG", "JPEGBTN", "FAX", "FAXBTN",
+    "AUDIOBTN", "TIME", "DATE", "URL", "SEARCHACT", "LINKACT", "ADDDNACT",
+    "VERIFYACT",
+};
+
+static char *syn_type[] = {
+    "?", "txt", "img", "?", "bool", "?", "?", "?", "btn",
+    "?", "?", "?", "?", "?", "?", "?",
+    "action", "?"
+};
+
+static char *includeattrs[] = { "objectClass", "sn", NULL };
+
+static char *item_opts[] = {
+    "ro", "sort", "1val", "hide", "required", "hideiffalse", NULL
+};
+
+static unsigned long item_opt_vals[] = {
+    LDAP_DITEM_OPT_READONLY,		LDAP_DITEM_OPT_SORTVALUES,
+    LDAP_DITEM_OPT_SINGLEVALUED,	LDAP_DITEM_OPT_HIDEIFEMPTY,
+    LDAP_DITEM_OPT_VALUEREQUIRED,	LDAP_DITEM_OPT_HIDEIFFALSE,
+};
+
+
+void
+dump_tmpl( struct ldap_disptmpl *tmpl )
+{
+    struct ldap_tmplitem	*rowp, *colp;
+    int				i, rowcnt, colcnt;
+    char			**fetchattrs;
+    struct ldap_oclist		*ocp;
+    struct ldap_adddeflist	*adp;
+
+    printf( "** Template \"%s\" (plural \"%s\", icon \"%s\")\n",
+	    NULLSTRINGIFNULL( tmpl->dt_name ),
+	    NULLSTRINGIFNULL( tmpl->dt_pluralname ),
+	    NULLSTRINGIFNULL( tmpl->dt_iconname ));
+
+    printf( "object class list:\n" );
+    for ( ocp = tmpl->dt_oclist; ocp != NULL; ocp = ocp->oc_next ) {
+	for ( i = 0; ocp->oc_objclasses[ i ] != NULL; ++i ) {
+	    printf( "%s%s", i == 0 ? "  " : " & ",
+		    NULLSTRINGIFNULL( ocp->oc_objclasses[ i ] ));
+	}
+	putchar( '\n' );
+    }
+    putchar( '\n' );
+
+    printf( "template options:          " );
+    if ( tmpl->dt_options == 0L ) {
+	printf( "NONE\n" );
+    } else {
+	printf( "%s %s %s\n", LDAP_IS_DISPTMPL_OPTION_SET( tmpl,
+		LDAP_DTMPL_OPT_ADDABLE ) ? "addable" : "",
+		LDAP_IS_DISPTMPL_OPTION_SET( tmpl, LDAP_DTMPL_OPT_ALLOWMODRDN )
+		? "modrdn" : "",
+		LDAP_IS_DISPTMPL_OPTION_SET( tmpl, LDAP_DTMPL_OPT_ALTVIEW )
+		? "altview" : "" );
+    }
+
+    printf( "authenticate as attribute: %s\n", tmpl->dt_authattrname != NULL ?
+	    tmpl->dt_authattrname : "<default>" );
+
+    printf( "default RDN attribute:     %s\n", tmpl->dt_defrdnattrname != NULL ?
+	    tmpl->dt_defrdnattrname : "NONE" );
+
+    printf( "default add location:      %s\n", tmpl->dt_defaddlocation != NULL ?
+	    tmpl->dt_defaddlocation : "NONE" );
+
+    printf( "\nnew entry value default rules:\n" );
+    for ( adp = tmpl->dt_adddeflist; adp != NULL; adp = adp->ad_next ) {
+	if ( adp->ad_source == LDAP_ADSRC_CONSTANTVALUE ) {
+	    printf( "  attribute %s <-- constant value \"%s\"\n",
+		NULLSTRINGIFNULL( adp->ad_attrname),
+		NULLSTRINGIFNULL( adp->ad_value ));
+	} else {
+	    printf( "  attribute %s <-- adder's DN\n",
+		    NULLSTRINGIFNULL( adp->ad_attrname ));
+	}
+    }
+    putchar( '\n' );
+
+    printf( "\nfetch attributes & values:\n" );
+    if (( fetchattrs = ldap_tmplattrs( tmpl, includeattrs, 1,
+		LDAP_SYN_OPT_DEFER )) == NULL ) {
+	printf( "  <none>\n" );
+    } else {
+	for ( i = 0; fetchattrs[ i ] != NULL; ++i ) {
+	    printf( "  %s\n", fetchattrs[ i ] );
+	    free( fetchattrs[ i ] );
+	}
+	free( (char *)fetchattrs );
+    }
+
+    printf( "\nfetch attributes only:\n" );
+    if (( fetchattrs = ldap_tmplattrs( tmpl, NULL, 0,
+		LDAP_SYN_OPT_DEFER )) == NULL ) {
+	printf( "  <none>\n" );
+    } else {
+	for ( i = 0; fetchattrs[ i ] != NULL; ++i ) {
+	    printf( "  %s\n", fetchattrs[ i ] );
+	    free( fetchattrs[ i ] );
+	}
+	free( (char *)fetchattrs );
+    }
+
+    printf( "\ntemplate items:\n" );
+    rowcnt = 0;
+    for ( rowp = ldap_first_tmplrow( tmpl ); rowp != NULLTMPLITEM;
+	    rowp = ldap_next_tmplrow( tmpl, rowp )) {
+	++rowcnt;
+	colcnt = 0;
+	for ( colp = ldap_first_tmplcol( tmpl, rowp ); colp != NULLTMPLITEM;
+		colp = ldap_next_tmplcol( tmpl, rowp, colp )) {
+	    ++colcnt;
+	    printf( "  %2d-%d: %s (%s%s", rowcnt, colcnt,
+		syn_name[ colp->ti_syntaxid & 0x0000FFFF ],
+		syn_type[ LDAP_GET_SYN_TYPE( colp->ti_syntaxid ) >> 24 ],
+		(( LDAP_GET_SYN_OPTIONS( colp->ti_syntaxid ) &
+		LDAP_SYN_OPT_DEFER ) != 0 ) ? ",defer" : "" );
+
+	    for ( i = 0; item_opts[ i ] != NULL; ++i ) {
+		if ( LDAP_IS_TMPLITEM_OPTION_SET( colp, item_opt_vals[ i ] )) {
+		    printf( ",%s", NULLSTRINGIFNULL( item_opts[ i ] ));
+		}
+	    }
+
+	    printf( "), %s, %s", NULLSTRINGIFNULL( colp->ti_attrname ),
+		    NULLSTRINGIFNULL( colp->ti_label ));
+	    if ( colp->ti_args != NULL ) {
+		printf( ",args=" );
+		for ( i = 0; colp->ti_args[ i ] != NULL; ++i ) {
+		    printf( "<%s>", NULLSTRINGIFNULL( colp->ti_args[ i ] ));
+		}
+	    }
+
+	    putchar( '\n' );
+	}
+    }
+}
+
+
+void
+dump_srchpref( struct ldap_searchobj *so )
+{
+    int i;
+    struct ldap_searchattr *sa;
+    struct ldap_searchmatch *sm;
+
+    printf( "Object type prompt:  %s\n",
+	    NULLSTRINGIFNULL( so->so_objtypeprompt ));
+    printf( "Options:             %s\n",
+	    LDAP_IS_SEARCHOBJ_OPTION_SET( so, LDAP_SEARCHOBJ_OPT_INTERNAL ) ?
+	    "internal" : "NONE" );
+    printf( "Prompt:              %s\n", NULLSTRINGIFNULL( so->so_prompt ));
+    printf( "Scope:               " );
+    switch ( so->so_defaultscope ) {
+    case LDAP_SCOPE_BASE:
+	printf( "LDAP_SCOPE_BASE" );
+	break;
+    case LDAP_SCOPE_ONELEVEL:
+	printf( "LDAP_SCOPE_ONELEVEL" );
+	break;
+    case LDAP_SCOPE_SUBTREE:
+	printf( "LDAP_SCOPE_SUBTREE" );
+	break;
+    default:
+	printf("*** unknown!" );
+    }
+    puts( "\n" );
+    printf( "Filter prefix:       %s\n",
+	    NULLSTRINGIFNULL( so->so_filterprefix ));
+    printf( "Filter tag:          %s\n",
+	    NULLSTRINGIFNULL( so->so_filtertag ));
+    printf( "Default select attr: %s\n",
+	    NULLSTRINGIFNULL( so->so_defaultselectattr ));
+    printf( "Default select text: %s\n",
+	    NULLSTRINGIFNULL( so->so_defaultselecttext ));
+    printf( "Searchable attributes ---- \n" );
+    for ( sa = so->so_salist; sa != NULL; sa = sa->sa_next ) {
+	printf( "  Label: %s\n", NULLSTRINGIFNULL( sa->sa_attrlabel ));
+	printf( "  Attribute: %s\n", NULLSTRINGIFNULL( sa->sa_attr ));
+	printf( "  Select attr: %s\n", NULLSTRINGIFNULL( sa->sa_selectattr ));
+	printf( "  Select text: %s\n", NULLSTRINGIFNULL( sa->sa_selecttext ));
+	printf( "  Match types ---- \n" );
+	for ( i = 0, sm = so->so_smlist; sm != NULL; i++, sm = sm->sm_next ) {
+	    if (( sa->sa_matchtypebitmap >> i ) & 1 ) {
+		printf( "    %s (%s)\n",
+			NULLSTRINGIFNULL( sm->sm_matchprompt ),
+			NULLSTRINGIFNULL( sm->sm_filter ));
+	    }
+	}
+    }
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/ufn.c
@@ -0,0 +1,563 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ *  Copyright (c) 1990 Regents of the University of Michigan.
+ *  All rights reserved.
+ */
+/*
+ *  ufn.c
+ */
+
+#if 0
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1993 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+typedef int (LDAP_CALL *cancelptype)( void *cancelparm );
+
+static int ldap_ufn_search_ctx( LDAP *ld, char **ufncomp, int ncomp, 
+	char *prefix, char **attrs, int attrsonly,
+	LDAPMessage **res, LDAP_CANCELPROC_CALLBACK *cancelproc, void *cancelparm,
+	char *tag1, char *tag2, char *tag3 );
+static LDAPMessage *ldap_msg_merge( LDAP *ld, LDAPMessage *a, LDAPMessage *b );
+static LDAPMessage *ldap_ufn_expand( LDAP *ld, 
+	LDAP_CANCELPROC_CALLBACK *cancelproc, void *cancelparm, char **dns, 
+	char *filter, int scope, char **attrs, int aonly, int *err );
+
+/*
+ * ldap_ufn_search_ctx - do user friendly searching; provide cancel feature;
+ *			specify ldapfilter.conf tags for each phase of search
+ *
+ *	ld		LDAP descriptor
+ *	ufncomp		the exploded user friendly name to look for
+ *	ncomp		number of elements in ufncomp
+ *	prefix		where to start searching
+ *	attrs		list of attribute types to return for matches
+ *	attrsonly	1 => attributes only 0 => attributes and values
+ *	res		will contain the result of the search
+ *	cancelproc	routine that returns non-zero if operation should be
+ *			cancelled.  This can be NULL.  If it is non-NULL, the
+ *			routine will be called periodically.
+ *	cancelparm	void * that is passed to cancelproc
+ *	tag[123]	the ldapfilter.conf tag that will be used in phases
+ *			1, 2, and 3 of the search, respectively
+ *
+ * Example:
+ *	char		*attrs[] = { "mail", "title", 0 };
+ *	char		*ufncomp[] = { "howes", "umich", "us", 0 }
+ *	LDAPMessage	*res;
+ *	error = ldap_ufn_search_ctx( ld, ufncomp, 3, NULL, attrs, attrsonly,
+ *			&res, acancelproc, along, "ufn first",
+ *			"ufn intermediate", "ufn last" );
+ */
+
+static int
+ldap_ufn_search_ctx(
+    LDAP 	*ld, 
+    char 	**ufncomp, 
+    int 	ncomp, 
+    char 	*prefix,
+    char 	**attrs,
+    int 	attrsonly, 
+    LDAPMessage **res, 
+    LDAP_CANCELPROC_CALLBACK *cancelproc,
+    void 	*cancelparm, 
+    char 	*tag1, 
+    char 	*tag2, 
+    char 	*tag3
+)
+{
+	char		*dn, *ftag = NULL;
+	char		**dns = NULL;
+	int		max, i, err, scope = 0, phase, tries;
+	LDAPFiltInfo	*fi;
+	LDAPMessage	*tmpcand;
+	LDAPMessage	*candidates;
+	static char	*objattrs[] = { "objectClass", NULL };
+
+	/* 
+	 * look up ufn components from most to least significant.
+	 * there are 3 phases.  
+	 * 	phase 1	search the root for orgs or countries
+	 * 	phase 2	search for orgs
+	 * 	phase 3	search for a person
+	 * in phases 1 and 2, we are building a list of candidate DNs,
+	 * below which we will search for the final component of the ufn.
+	 * for each component we try the filters listed in the
+	 * filterconfig file, first one-level (except the last compoment),
+	 * then subtree.  if any of them produce any results, we go on to
+	 * the next component.
+	 */
+
+	*res = NULL;
+	candidates = NULL;
+	phase = 1;
+	for ( ncomp--; ncomp != -1; ncomp-- ) {
+		if ( *ufncomp[ncomp] == '"' ) {
+			char	*quote;
+
+			if ( (quote = strrchr( ufncomp[ncomp], '"' )) != NULL )
+				*quote = '\0';
+			strcpy( ufncomp[ncomp], ufncomp[ncomp] + 1 );
+		}
+		if ( ncomp == 0 )
+			phase = 3;
+
+		switch ( phase ) {
+		case 1:
+			ftag = tag1;
+			scope = LDAP_SCOPE_ONELEVEL;
+			break;
+		case 2:
+			ftag = tag2;
+			scope = LDAP_SCOPE_ONELEVEL;
+			break;
+		case 3:
+			ftag = tag3;
+			scope = LDAP_SCOPE_SUBTREE;
+			break;
+		}
+
+		/*
+		 * construct an array of DN's to search below from the
+		 * list of candidates.
+		 */
+
+		if ( candidates == NULL ) {
+			if ( prefix != NULL ) {
+				if ( (dns = (char **)NSLDAPI_MALLOC(
+				    sizeof(char *) * 2 )) == NULL ) {
+					err = LDAP_NO_MEMORY;
+					LDAP_SET_LDERRNO( ld, err, NULL, NULL );
+					return( err );
+				}
+				dns[0] = nsldapi_strdup( prefix );
+				dns[1] = NULL;
+			} else {
+				dns = NULL;
+			}
+		} else {
+			i = 0, max = 0;
+			for ( tmpcand = candidates; tmpcand != NULL &&
+			    tmpcand->lm_msgtype != LDAP_RES_SEARCH_RESULT;
+			    tmpcand = tmpcand->lm_chain )
+			{
+				if ( (dn = ldap_get_dn( ld, tmpcand )) == NULL )
+					continue;
+
+				if ( dns == NULL ) {
+					if ( (dns = (char **)NSLDAPI_MALLOC(
+					    sizeof(char *) * 8 )) == NULL ) {
+						err = LDAP_NO_MEMORY;
+						LDAP_SET_LDERRNO( ld, err,
+						    NULL, NULL );
+						return( err );
+					}
+					max = 8;
+				} else if ( i >= max ) {
+					if ( (dns = (char **)NSLDAPI_REALLOC(
+					    dns, sizeof(char *) * 2 * max ))
+					    == NULL ) {
+						err = LDAP_NO_MEMORY;
+						LDAP_SET_LDERRNO( ld, err,
+						    NULL, NULL );
+						return( err );
+					}
+					max *= 2;
+				}
+				dns[i++] = dn;
+				dns[i] = NULL;
+			}
+			ldap_msgfree( candidates );
+			candidates = NULL;
+		}
+		tries = 0;
+	tryagain:
+		tries++;
+		for ( fi = ldap_getfirstfilter( ld->ld_filtd, ftag,
+		    ufncomp[ncomp] ); fi != NULL;
+		    fi = ldap_getnextfilter( ld->ld_filtd ) )
+		{
+			if ( (candidates = ldap_ufn_expand( ld, cancelproc,
+			    cancelparm, dns, fi->lfi_filter, scope,
+			    phase == 3 ? attrs : objattrs,
+			    phase == 3 ? attrsonly : 1, &err )) != NULL )
+			{
+				break;
+			}
+
+			if ( err == -1 || err == LDAP_USER_CANCELLED ) {
+				if ( dns != NULL ) {
+					ldap_value_free( dns );
+					dns = NULL;
+				}
+				return( err );
+			}
+		}
+
+		if ( candidates == NULL ) {
+			if ( tries < 2 && phase != 3 ) {
+				scope = LDAP_SCOPE_SUBTREE;
+				goto tryagain;
+			} else {
+				if ( dns != NULL ) {
+					ldap_value_free( dns );
+					dns = NULL;
+				}
+				return( err );
+			}
+		}
+
+		/* go on to the next component */
+		if ( phase == 1 )
+			phase++;
+		if ( dns != NULL ) {
+			ldap_value_free( dns );
+			dns = NULL;
+		}
+	}
+	*res = candidates;
+
+	return( err );
+}
+
+int
+LDAP_CALL
+ldap_ufn_search_ct( LDAP *ld, char *ufn, char **attrs, int attrsonly,
+	LDAPMessage **res, LDAP_CANCELPROC_CALLBACK *cancelproc, void *cancelparm,
+	char *tag1, char *tag2, char *tag3 )
+{
+	char	**ufncomp, **prefixcomp;
+	char	*pbuf;
+	int	ncomp, pcomp, i, err = 0;
+
+	/* getfilter stuff must be inited before we are called */
+	if ( ld->ld_filtd == NULL ) {
+		err = LDAP_PARAM_ERROR;
+		LDAP_SET_LDERRNO( ld, err, NULL, NULL );
+		return( err );
+	}
+
+	/* call ldap_explode_dn() to break the ufn into its components */
+	if ( (ufncomp = ldap_explode_dn( ufn, 0 )) == NULL ) {
+		err = LDAP_LOCAL_ERROR;
+		LDAP_SET_LDERRNO( ld, err, NULL, NULL );
+		return( err );
+	}
+	for ( ncomp = 0; ufncomp[ncomp] != NULL; ncomp++ )
+		;	/* NULL */
+
+	/* more than two components => try it fully qualified first */
+	if ( ncomp > 2 || ld->ld_ufnprefix == NULL ) {
+		err = ldap_ufn_search_ctx( ld, ufncomp, ncomp, NULL, attrs,
+		    attrsonly, res, cancelproc, cancelparm, tag1, tag2, tag3 );
+
+		if ( ldap_count_entries( ld, *res ) > 0 ) {
+			ldap_value_free( ufncomp );
+			return( err );
+		} else {
+			ldap_msgfree( *res );
+			*res = NULL;
+		}
+	}
+
+	if ( ld->ld_ufnprefix == NULL ) {
+		ldap_value_free( ufncomp );
+		return( err );
+	}
+
+	/* if that failed, or < 2 components, use the prefix */
+	if ( (prefixcomp = ldap_explode_dn( ld->ld_ufnprefix, 0 )) == NULL ) {
+		ldap_value_free( ufncomp );
+		err = LDAP_LOCAL_ERROR;
+		LDAP_SET_LDERRNO( ld, err, NULL, NULL );
+		return( err );
+	}
+	for ( pcomp = 0; prefixcomp[pcomp] != NULL; pcomp++ )
+		;	/* NULL */
+	if ( (pbuf = (char *)NSLDAPI_MALLOC( strlen( ld->ld_ufnprefix ) + 1 ))
+	    == NULL ) {	
+		ldap_value_free( ufncomp );
+		ldap_value_free( prefixcomp );
+		err = LDAP_NO_MEMORY;
+		LDAP_SET_LDERRNO( ld, err, NULL, NULL );
+		return( err );
+	}
+
+	for ( i = 0; i < pcomp; i++ ) {
+		int	j;
+
+		*pbuf = '\0';
+		for ( j = i; j < pcomp; j++ ) {
+			strcat( pbuf, prefixcomp[j] );
+			if ( j + 1 < pcomp )
+				strcat( pbuf, "," );
+		}
+		err = ldap_ufn_search_ctx( ld, ufncomp, ncomp, pbuf, attrs,
+		    attrsonly, res, cancelproc, cancelparm, tag1, tag2, tag3 );
+
+		if ( ldap_count_entries( ld, *res ) > 0 ) {
+			break;
+		} else {
+			ldap_msgfree( *res );
+			*res = NULL;
+		}
+	}
+
+	ldap_value_free( ufncomp );
+	ldap_value_free( prefixcomp );
+	NSLDAPI_FREE( pbuf );
+
+	return( err );
+}
+
+/*
+ * same as ldap_ufn_search_ct, except without the ability to specify
+ * ldapfilter.conf tags.
+ */
+int
+LDAP_CALL
+ldap_ufn_search_c( LDAP *ld, char *ufn, char **attrs, int attrsonly,
+	LDAPMessage **res, LDAP_CANCELPROC_CALLBACK *cancelproc, void *cancelparm )
+{
+	return( ldap_ufn_search_ct( ld, ufn, attrs, attrsonly, res, cancelproc,
+	    cancelparm, "ufn first", "ufn intermediate", "ufn last" ) );
+}
+
+/*
+ * same as ldap_ufn_search_c without the cancel function
+ */
+int
+LDAP_CALL
+ldap_ufn_search_s( LDAP *ld, char *ufn, char **attrs, int attrsonly,
+	LDAPMessage **res )
+{
+	struct timeval	tv;
+
+	tv.tv_sec = ld->ld_timelimit;
+
+	return( ldap_ufn_search_ct( ld, ufn, attrs, attrsonly, res,
+		ld->ld_timelimit ? ldap_ufn_timeout : NULL,
+		ld->ld_timelimit ? (void *) &tv : NULL,
+		"ufn first", "ufn intermediate", "ufn last" ) );
+}
+
+
+/*
+ * ldap_msg_merge - merge two ldap search result chains.  the more
+ * serious of the two error result codes is kept.
+ */
+
+static LDAPMessage *
+ldap_msg_merge( LDAP *ld, LDAPMessage *a, LDAPMessage *b )
+{
+	LDAPMessage	*end, *aprev, *aend, *bprev, *bend;
+
+	if ( a == NULL )
+		return( b );
+
+	if ( b == NULL )
+		return( a );
+
+	/* find the ends of the a and b chains */
+	aprev = NULL;
+	for ( aend = a; aend->lm_chain != NULL; aend = aend->lm_chain )
+		aprev = aend;
+	bprev = NULL;
+	for ( bend = b; bend->lm_chain != NULL; bend = bend->lm_chain )
+		bprev = bend;
+
+	/* keep result a */
+	if ( ldap_result2error( ld, aend, 0 ) != LDAP_SUCCESS ) {
+		/* remove result b */
+		ldap_msgfree( bend );
+		if ( bprev != NULL )
+			bprev->lm_chain = NULL;
+		else
+			b = NULL;
+		end = aend;
+		if ( aprev != NULL )
+			aprev->lm_chain = NULL;
+		else
+			a = NULL;
+	/* keep result b */
+	} else {
+		/* remove result a */
+		ldap_msgfree( aend );
+		if ( aprev != NULL )
+			aprev->lm_chain = NULL;
+		else
+			a = NULL;
+		end = bend;
+		if ( bprev != NULL )
+			bprev->lm_chain = NULL;
+		else
+			b = NULL;
+	}
+
+	if ( (a == NULL && b == NULL) || (a == NULL && bprev == NULL) ||
+	    (b == NULL && aprev == NULL) )
+		return( end );
+
+	if ( a == NULL ) {
+		bprev->lm_chain = end;
+		return( b );
+	} else if ( b == NULL ) {
+		aprev->lm_chain = end;
+		return( a );
+	} else {
+		bprev->lm_chain = end;
+		aprev->lm_chain = b;
+		return( a );
+	}
+}
+
+static LDAPMessage *
+ldap_ufn_expand( LDAP *ld, LDAP_CANCELPROC_CALLBACK *cancelproc, 
+	void *cancelparm, char **dns, char *filter, int scope, 
+	char **attrs, int aonly, int *err )
+{
+	LDAPMessage	*tmpcand, *tmpres;
+	char		*dn;
+	int		i, msgid;
+	struct timeval	tv;
+
+	/* search for this component below the current candidates */
+	tmpcand = NULL;
+	i = 0;
+	do {
+		if ( dns != NULL )
+			dn = dns[i];
+		else
+			dn = "";
+
+		if (( msgid = ldap_search( ld, dn, scope, filter, attrs,
+		    aonly )) == -1 ) {
+			ldap_msgfree( tmpcand );
+                        tmpcand = NULL;
+			*err = LDAP_GET_LDERRNO( ld, NULL, NULL );
+                        /*
+                         * Compiling with gcc-4.2 on Mac:
+                         * gcc-4.2 -arch ppc -c -o ufn.o -gdwarf-2 -01 ufn.c
+                         * having a return NULL statement here causes gcc to
+                         * hang. Therefore set tmpcand to null (above) and break
+                         * out of this loop to make gcc happy.
+                         */
+                        break;
+		}
+
+		tv.tv_sec = 0;
+		tv.tv_usec = 100000;	/* 1/10 of a second */
+
+		do {
+			*err = ldap_result( ld, msgid, 1, &tv, &tmpres );
+			if ( *err == 0 && cancelproc != NULL &&
+			    (*cancelproc)( cancelparm ) != 0 ) {
+				ldap_abandon( ld, msgid );
+				*err = LDAP_USER_CANCELLED;
+				LDAP_SET_LDERRNO( ld, *err, NULL, NULL );
+			}
+		} while ( *err == 0 );
+
+		if ( *err == LDAP_USER_CANCELLED || *err < 0 ||
+		    ( *err = ldap_result2error( ld, tmpres, 0 )) == -1 ) {
+			ldap_msgfree( tmpcand );
+			return( NULL );
+		}
+		
+		tmpcand = ldap_msg_merge( ld, tmpcand, tmpres );
+
+		i++;
+	} while ( dns != NULL && dns[i] != NULL );
+
+        /* Catch the tmpcand = NULL case as required by breaking out the loop
+         * to prevent gcc-4.2 hanging on Mac.
+         */
+        if (!tmpcand)
+          return NULL;
+
+	if ( ldap_count_entries( ld, tmpcand ) > 0 ) {
+		return( tmpcand );
+	} else {
+		ldap_msgfree( tmpcand );
+		return( NULL );
+	}
+}
+
+/*
+ * ldap_ufn_setfilter - set the filter config file used in ufn searching
+ */
+
+LDAPFiltDesc *
+LDAP_CALL
+ldap_ufn_setfilter( LDAP *ld, char *fname )
+{
+	if ( ld->ld_filtd != NULL )
+		ldap_getfilter_free( ld->ld_filtd );
+
+	return( ld->ld_filtd = ldap_init_getfilter( fname ) );
+}
+
+void
+LDAP_CALL
+ldap_ufn_setprefix( LDAP *ld, char *prefix )
+{
+	if ( ld->ld_ufnprefix != NULL )
+		NSLDAPI_FREE( ld->ld_ufnprefix );
+
+	ld->ld_ufnprefix = nsldapi_strdup( prefix );
+}
+
+int
+LDAP_C
+ldap_ufn_timeout( void *tvparam )
+{
+	struct timeval	*tv;
+
+	tv = (struct timeval *)tvparam;
+
+	if ( tv->tv_sec != 0 ) {
+		tv->tv_usec = tv->tv_sec * 1000000;	/* sec => micro sec */
+		tv->tv_sec = 0;
+	}
+	tv->tv_usec -= 100000;	/* 1/10 of a second */
+
+	return( tv->tv_usec <= 0 ? 1 : 0 );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/unbind.c
@@ -0,0 +1,248 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ *  Copyright (c) 1990 Regents of the University of Michigan.
+ *  All rights reserved.
+ */
+
+/*
+ *  unbind.c
+ */
+
+#if 0
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+int
+LDAP_CALL
+ldap_unbind( LDAP *ld )
+{
+	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_unbind\n", 0, 0, 0 );
+
+	return( ldap_ld_free( ld, NULL, NULL, 1 ) );
+}
+
+
+int
+LDAP_CALL
+ldap_unbind_s( LDAP *ld )
+{
+	return( ldap_ld_free( ld, NULL, NULL, 1 ));
+}
+
+
+int
+LDAP_CALL
+ldap_unbind_ext( LDAP *ld, LDAPControl **serverctrls,
+    LDAPControl **clientctrls )
+{
+	return( ldap_ld_free( ld, serverctrls, clientctrls, 1 ));
+}
+
+
+/*
+ * Dispose of the LDAP session ld, including all associated connections
+ * and resources.  If close is non-zero, an unbind() request is sent as well.
+ */
+int
+ldap_ld_free( LDAP *ld, LDAPControl **serverctrls,
+    LDAPControl **clientctrls, int close )
+{
+	LDAPMessage	*lm, *next;
+	int		err = LDAP_SUCCESS;
+	LDAPRequest	*lr, *nextlr;
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( LDAP_PARAM_ERROR );
+	}
+
+	if ( ld->ld_sbp->sb_naddr == 0 ) {
+		LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
+		/* free LDAP structure and outstanding requests/responses */
+		for ( lr = ld->ld_requests; lr != NULL; lr = nextlr ) {
+			nextlr = lr->lr_next;
+			nsldapi_free_request( ld, lr, 0 );
+		}
+		LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
+
+		/* free and unbind from all open connections */
+		LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK );
+		while ( ld->ld_conns != NULL ) {
+			nsldapi_free_connection( ld, ld->ld_conns, serverctrls,
+			    clientctrls, 1, close );
+		}
+		LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
+
+	} else {
+		int	i;
+
+		for ( i = 0; i < ld->ld_sbp->sb_naddr; ++i ) {
+			NSLDAPI_FREE( ld->ld_sbp->sb_addrs[ i ] );
+		}
+		NSLDAPI_FREE( ld->ld_sbp->sb_addrs );
+		NSLDAPI_FREE( ld->ld_sbp->sb_fromaddr );
+	}
+
+	LDAP_MUTEX_LOCK( ld, LDAP_RESP_LOCK );
+	for ( lm = ld->ld_responses; lm != NULL; lm = next ) {
+		next = lm->lm_next;
+		ldap_msgfree( lm );
+	}
+	LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
+
+	/* call cache unbind function to allow it to clean up after itself */
+	if ( ld->ld_cache_unbind != NULL ) {
+		LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK );
+		(void)ld->ld_cache_unbind( ld, 0, 0 );
+		LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
+	}
+
+	/* call the dispose handle I/O callback if one is defined */
+	if ( ld->ld_extdisposehandle_fn != NULL ) {
+	    /*
+	     * We always pass the session extended I/O argument to
+	     * the dispose handle callback.
+	     */
+	    ld->ld_extdisposehandle_fn( ld, ld->ld_ext_session_arg );
+	}
+
+	if ( ld->ld_error != NULL )
+		NSLDAPI_FREE( ld->ld_error );
+	if ( ld->ld_matched != NULL )
+		NSLDAPI_FREE( ld->ld_matched );
+	if ( ld->ld_host != NULL )
+		NSLDAPI_FREE( ld->ld_host );
+	if ( ld->ld_ufnprefix != NULL )
+		NSLDAPI_FREE( ld->ld_ufnprefix );
+	if ( ld->ld_filtd != NULL )
+		ldap_getfilter_free( ld->ld_filtd );
+	if ( ld->ld_abandoned != NULL )
+		NSLDAPI_FREE( ld->ld_abandoned );
+	if ( ld->ld_sbp != NULL )
+		ber_sockbuf_free( ld->ld_sbp );
+	if ( ld->ld_defhost != NULL )
+		NSLDAPI_FREE( ld->ld_defhost );
+	if ( ld->ld_servercontrols != NULL )
+		ldap_controls_free( ld->ld_servercontrols );
+	if ( ld->ld_clientcontrols != NULL )
+		ldap_controls_free( ld->ld_clientcontrols );
+	if ( ld->ld_preferred_language != NULL )
+		NSLDAPI_FREE( ld->ld_preferred_language );
+	nsldapi_iostatus_free( ld );
+#ifdef LDAP_SASLIO_HOOKS
+	NSLDAPI_FREE( ld->ld_def_sasl_mech );
+	NSLDAPI_FREE( ld->ld_def_sasl_realm );
+	NSLDAPI_FREE( ld->ld_def_sasl_authcid );
+	NSLDAPI_FREE( ld->ld_def_sasl_authzid );
+#endif
+
+	/*
+	 * XXXmcs: should use cache function pointers to hook in memcache
+	 */
+	if ( ld->ld_memcache != NULL ) {
+		ldap_memcache_set( ld, NULL );
+	}
+
+	/* free all mutexes we have allocated */
+	nsldapi_mutex_free_all( ld );
+	NSLDAPI_FREE( ld->ld_mutex );
+
+	NSLDAPI_FREE( (char *) ld );
+
+	return( err );
+}
+
+
+
+int
+nsldapi_send_unbind( LDAP *ld, Sockbuf *sb, LDAPControl **serverctrls,
+    LDAPControl **clientctrls )
+{
+	BerElement	*ber;
+	int		err, msgid;
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_send_unbind\n", 0, 0, 0 );
+
+	/* create a message to send */
+	if (( err = nsldapi_alloc_ber_with_options( ld, &ber ))
+	    != LDAP_SUCCESS ) {
+		return( err );
+	}
+
+	/* fill it in */
+	LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK );
+	msgid = ++ld->ld_msgid;
+	LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK );
+
+	if ( ber_printf( ber, "{itn", msgid, LDAP_REQ_UNBIND ) == -1 ) {
+		ber_free( ber, 1 );
+		err = LDAP_ENCODING_ERROR;
+		LDAP_SET_LDERRNO( ld, err, NULL, NULL );
+		return( err );
+	}
+
+	if (( err = nsldapi_put_controls( ld, serverctrls, 1, ber ))
+	    != LDAP_SUCCESS ) {
+		ber_free( ber, 1 );
+		return( err );
+	}
+
+	/* send the message */
+        err = nsldapi_send_ber_message( ld, sb, ber, 1 /* free ber */,
+        	0 /* will not handle EPIPE */ );
+	if ( err != 0 ) {
+		ber_free( ber, 1 );
+		if (err != -2 ) {
+			/*
+			 * Message could not be sent, and the reason is
+			 * something other than a "would block" error.
+			 * Note that we ignore "would block" errors because
+			 * it is not critical that an UnBind request
+			 * actually reach the LDAP server.
+			 */
+			err = LDAP_SERVER_DOWN;
+			LDAP_SET_LDERRNO( ld, err, NULL, NULL );
+			return( err );
+		}
+	}
+
+	return( LDAP_SUCCESS );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/unescape.c
@@ -0,0 +1,81 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ *  LIBLDAP unescape.c -- LDAP URL un-escape routines
+ *  We also tolerate URLs that look like: <ldapurl> and <URL:ldapurl>
+ */
+
+#include "ldap-int.h"
+
+
+static int unhex( char c );
+
+
+void
+nsldapi_hex_unescape( char *s )
+{
+/*
+ * Remove URL hex escapes from s... done in place.  The basic concept for
+ * this routine is borrowed from the WWW library HTUnEscape() routine.
+ */
+	char	*p;
+
+	for ( p = s; *s != '\0'; ++s ) {
+		if ( *s == '%' ) {
+			if ( *++s != '\0' ) {
+				*p = unhex( *s ) << 4;
+			}
+			if ( *++s != '\0' ) {
+				*p++ += unhex( *s );
+			}
+		} else {
+			*p++ = *s;
+		}
+	}
+
+	*p = '\0';
+}
+
+
+static int
+unhex( char c )
+{
+	return( c >= '0' && c <= '9' ? c - '0'
+	    : c >= 'A' && c <= 'F' ? c - 'A' + 10
+	    : c - 'a' + 10 );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/url.c
@@ -0,0 +1,527 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+/*
+ *  Copyright (c) 1996 Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ */
+/*  LIBLDAP url.c -- LDAP URL related routines
+ *
+ *  LDAP URLs look like this:
+ *    l d a p : / / [ hostport ] [ / dn [ ? [ attributes ] [ ? [ scope ]
+ *			[ ? [ filter ] [ ? extensions ] ] ] ] ]
+ *
+ *  where:
+ *   hostport is a host or a host:port list that can be space-separated.
+ *   attributes is a comma separated list
+ *   scope is one of these three strings:  base one sub (default=base)
+ *   filter is a string-represented filter as in RFC 2254
+ *   extensions is a comma-separated list of name=value pairs.
+ *
+ *  e.g.,  ldap://ldap.itd.umich.edu/c=US?o,description?one?o=umich
+ *
+ *  To accomodate IPv6 addresses, the host portion of a host that appears
+ *  in hostport can be enclosed in square brackets, e.g
+ *
+ *  e.g.,  ldap://[fe80::a00:20ff:fee5:c0b4]:3389/dc=siroe,dc=com
+ *
+ *  We also tolerate URLs that look like: <ldapurl> and <URL:ldapurl>
+ */
+
+#if 0
+#ifndef lint 
+static char copyright[] = "@(#) Copyright (c) 1996 Regents of the University of Michigan.\nAll rights reserved.\n";
+#endif
+#endif
+
+#include "ldap-int.h"
+
+
+static int skip_url_prefix( const char **urlp, int *enclosedp, int *securep );
+
+
+int
+LDAP_CALL
+ldap_is_ldap_url( const char *url )
+{
+	int	enclosed, secure;
+
+	return( url != NULL
+	    && skip_url_prefix( &url, &enclosed, &secure ));
+}
+
+
+static int
+skip_url_prefix( const char **urlp, int *enclosedp, int *securep )
+{
+/*
+ * return non-zero if this looks like a LDAP URL; zero if not
+ * if non-zero returned, *urlp will be moved past "ldap://" part of URL
+ * The data that *urlp points to is not changed by this function.
+ */
+	if ( *urlp == NULL ) {
+		return( 0 );
+	}
+
+	/* skip leading '<' (if any) */
+	if ( **urlp == '<' ) {
+		*enclosedp = 1;
+		++*urlp;
+	} else {
+		*enclosedp = 0;
+	}
+
+	/* skip leading "URL:" (if any) */
+	if ( strlen( *urlp ) >= LDAP_URL_URLCOLON_LEN && strncasecmp(
+	    *urlp, LDAP_URL_URLCOLON, LDAP_URL_URLCOLON_LEN ) == 0 ) {
+		*urlp += LDAP_URL_URLCOLON_LEN;
+	}
+
+	/* check for an "ldap://" prefix */
+	if ( strlen( *urlp ) >= LDAP_URL_PREFIX_LEN && strncasecmp( *urlp,
+	    LDAP_URL_PREFIX, LDAP_URL_PREFIX_LEN ) == 0 ) {
+		/* skip over URL prefix and return success */
+		*urlp += LDAP_URL_PREFIX_LEN;
+		*securep = 0;
+		return( 1 );
+	}
+
+	/* check for an "ldaps://" prefix */
+	if ( strlen( *urlp ) >= LDAPS_URL_PREFIX_LEN && strncasecmp( *urlp,
+	    LDAPS_URL_PREFIX, LDAPS_URL_PREFIX_LEN ) == 0 ) {
+		/* skip over URL prefix and return success */
+		*urlp += LDAPS_URL_PREFIX_LEN;
+		*securep = 1;
+		return( 1 );
+	}
+
+	return( 0 );	/* not an LDAP URL */
+}
+
+
+int
+LDAP_CALL
+ldap_url_parse_no_defaults( const char *url, LDAPURLDesc **ludpp, int dn_required)
+{
+    return( nsldapi_url_parse( url, ludpp, dn_required ) );
+}
+
+
+int
+LDAP_CALL
+ldap_url_parse( const char *url, LDAPURLDesc **ludpp )
+{
+/*
+ *  Pick apart the pieces of an LDAP URL.
+ */
+	int	rc;
+
+	if (( rc = nsldapi_url_parse( url, ludpp, 1 )) == 0 ) {
+		if ( (*ludpp)->lud_scope == -1 ) {
+			(*ludpp)->lud_scope = LDAP_SCOPE_BASE;
+		}
+		if ( (*ludpp)->lud_filter == NULL ) {
+			(*ludpp)->lud_filter = "(objectclass=*)";
+		}
+		if ( *((*ludpp)->lud_dn) == '\0' ) {
+			(*ludpp)->lud_dn = NULL;
+		}
+	} else if ( rc == LDAP_URL_UNRECOGNIZED_CRITICAL_EXTENSION ) {
+		rc = LDAP_URL_ERR_PARAM;	/* mapped for backwards compatibility */
+	}
+
+	return( rc );
+}
+
+
+/*
+ * like ldap_url_parse() with a few exceptions:
+ *   1) if dn_required is zero, a missing DN does not generate an error
+ *	(we just leave the lud_dn field NULL)
+ *   2) no defaults are set for lud_scope and lud_filter (they are set to -1
+ *	and NULL respectively if no SCOPE or FILTER are present in the URL).
+ *   3) when there is a zero-length DN in a URL we do not set lud_dn to NULL.
+ *
+ * note that LDAPv3 URL extensions are ignored unless they are marked
+ * critical, in which case an LDAP_URL_UNRECOGNIZED_CRITICAL_EXTENSION error
+ * is returned.
+ */
+int
+nsldapi_url_parse( const char *url, LDAPURLDesc **ludpp, int dn_required )
+{
+
+	LDAPURLDesc	*ludp;
+	char		*urlcopy, *attrs, *scope, *extensions = NULL, *p, *q;
+	int		enclosed, secure, i, nattrs, at_start;
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_url_parse(%s)\n", url, 0, 0 );
+
+	if ( url == NULL || ludpp == NULL ) {
+		return( LDAP_URL_ERR_PARAM );
+	}
+
+	*ludpp = NULL;	/* pessimistic */
+
+	if ( !skip_url_prefix( &url, &enclosed, &secure )) {
+		return( LDAP_URL_ERR_NOTLDAP );
+	}
+
+	/* allocate return struct */
+	if (( ludp = (LDAPURLDesc *)NSLDAPI_CALLOC( 1, sizeof( LDAPURLDesc )))
+	    == NULLLDAPURLDESC ) {
+		return( LDAP_URL_ERR_MEM );
+	}
+
+	if ( secure ) {
+		ludp->lud_options |= LDAP_URL_OPT_SECURE;
+	}
+
+	/* make working copy of the remainder of the URL */
+	if (( urlcopy = nsldapi_strdup( url )) == NULL ) {
+		ldap_free_urldesc( ludp );
+		return( LDAP_URL_ERR_MEM );
+	}
+
+	if ( enclosed && *((p = urlcopy + strlen( urlcopy ) - 1)) == '>' ) {
+		*p = '\0';
+	}
+
+	/* initialize scope and filter */
+	ludp->lud_scope = -1;
+	ludp->lud_filter = NULL;
+
+	/* lud_string is the only malloc'd string space we use */
+	ludp->lud_string = urlcopy;
+
+	/* scan forward for '/' that marks end of hostport and begin. of dn */
+	if (( ludp->lud_dn = strchr( urlcopy, '/' )) == NULL ) {
+		if ( dn_required ) {
+			ldap_free_urldesc( ludp );
+			return( LDAP_URL_ERR_NODN );
+		}
+	} else {
+		/* terminate hostport; point to start of dn */
+		*ludp->lud_dn++ = '\0';
+	}
+
+
+	if ( *urlcopy == '\0' ) {
+		ludp->lud_host = NULL;
+	} else {
+		ludp->lud_host = urlcopy;
+		nsldapi_hex_unescape( ludp->lud_host );
+
+		/*
+		 * Locate and strip off optional port number (:#) in host
+		 * portion of URL.
+		 *
+		 * If more than one space-separated host is listed, we only
+		 * look for a port number within the right-most one since
+		 * ldap_init() will handle host parameters that look like
+		 * host:port anyway.
+		 */
+		if (( p = strrchr( ludp->lud_host, ' ' )) == NULL ) {
+			p = ludp->lud_host;
+		} else {
+			++p;
+		}
+		if ( *p == '[' && ( q = strchr( p, ']' )) != NULL ) {
+			 /* square brackets present -- skip past them */
+			p = q++;
+		}
+		if (( p = strchr( p, ':' )) != NULL ) {
+			*p++ = '\0';
+			ludp->lud_port = atoi( p );
+			if ( *ludp->lud_host == '\0' ) {
+				ludp->lud_host = NULL;  /* no hostname */
+			}
+		}
+	}
+
+	/* scan for '?' that marks end of dn and beginning of attributes */
+	attrs = NULL;
+	if ( ludp->lud_dn != NULL &&
+	    ( attrs = strchr( ludp->lud_dn, '?' )) != NULL ) {
+		/* terminate dn; point to start of attrs. */
+		*attrs++ = '\0';
+
+		/* scan for '?' that marks end of attrs and begin. of scope */
+		if (( p = strchr( attrs, '?' )) != NULL ) {
+			/*
+			 * terminate attrs; point to start of scope and scan for
+			 * '?' that marks end of scope and begin. of filter
+			 */
+			*p++ = '\0';
+			scope = p;
+
+			if (( p = strchr( scope, '?' )) != NULL ) {
+				/* terminate scope; point to start of filter */
+				*p++ = '\0';
+				if ( *p != '\0' ) {
+					ludp->lud_filter = p;
+					/*
+					 * scan for the '?' that marks the end
+					 * of the filter and the start of any
+					 * extensions
+					 */
+					if (( p = strchr( ludp->lud_filter, '?' ))
+					    != NULL ) {
+						*p++ = '\0'; /* term. filter */
+						extensions = p;
+					}
+					if ( *ludp->lud_filter == '\0' ) {
+						ludp->lud_filter = NULL;
+					} else {
+						nsldapi_hex_unescape( ludp->lud_filter );
+					}
+				}
+			}
+
+			if ( strcasecmp( scope, "one" ) == 0 ) {
+				ludp->lud_scope = LDAP_SCOPE_ONELEVEL;
+			} else if ( strcasecmp( scope, "base" ) == 0 ) {
+				ludp->lud_scope = LDAP_SCOPE_BASE;
+			} else if ( strcasecmp( scope, "sub" ) == 0 ) {
+				ludp->lud_scope = LDAP_SCOPE_SUBTREE;
+			} else if ( *scope != '\0' ) {
+				ldap_free_urldesc( ludp );
+				return( LDAP_URL_ERR_BADSCOPE );
+			}
+		}
+	}
+
+	if ( ludp->lud_dn != NULL ) {
+		nsldapi_hex_unescape( ludp->lud_dn );
+	}
+
+	/*
+	 * if attrs list was included, turn it into a null-terminated array
+	 */
+	if ( attrs != NULL && *attrs != '\0' ) {
+		nsldapi_hex_unescape( attrs );
+		for ( nattrs = 1, p = attrs; *p != '\0'; ++p ) {
+		    if ( *p == ',' ) {
+			    ++nattrs;
+		    }
+		}
+
+		if (( ludp->lud_attrs = (char **)NSLDAPI_CALLOC( nattrs + 1,
+		    sizeof( char * ))) == NULL ) {
+			ldap_free_urldesc( ludp );
+			return( LDAP_URL_ERR_MEM );
+		}
+
+		for ( i = 0, p = attrs; i < nattrs; ++i ) {
+			ludp->lud_attrs[ i ] = p;
+			if (( p = strchr( p, ',' )) != NULL ) {
+				*p++ ='\0';
+			}
+			nsldapi_hex_unescape( ludp->lud_attrs[ i ] );
+		}
+	}
+
+	/* if extensions list was included, check for critical ones */
+	if ( extensions != NULL && *extensions != '\0' ) {
+		/* Note: at present, we do not recognize ANY extensions */
+		at_start = 1;
+		for ( p = extensions; *p != '\0'; ++p ) {
+			if ( at_start ) {
+				if ( *p == '!' ) {	/* critical extension */
+					ldap_free_urldesc( ludp );
+					return( LDAP_URL_UNRECOGNIZED_CRITICAL_EXTENSION );
+				}
+				at_start = 0;
+			} else if ( *p == ',' ) {
+				at_start = 1;
+			}
+		}
+	}
+
+	*ludpp = ludp;
+
+	return( 0 );
+}
+
+
+void
+LDAP_CALL
+ldap_free_urldesc( LDAPURLDesc *ludp )
+{
+	if ( ludp != NULLLDAPURLDESC ) {
+		if ( ludp->lud_string != NULL ) {
+			NSLDAPI_FREE( ludp->lud_string );
+		}
+		if ( ludp->lud_attrs != NULL ) {
+			NSLDAPI_FREE( ludp->lud_attrs );
+		}
+		NSLDAPI_FREE( ludp );
+	}
+}
+
+
+int
+LDAP_CALL
+ldap_url_search( LDAP *ld, const char *url, int attrsonly )
+{
+	int		err, msgid;
+	LDAPURLDesc	*ludp;
+	BerElement	*ber;
+	LDAPServer	*srv;
+	char		*host;
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( -1 );		/* punt */
+	}
+
+	if ( ldap_url_parse( url, &ludp ) != 0 ) {
+		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+		return( -1 );
+	}
+
+	LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK );
+	msgid = ++ld->ld_msgid;
+	LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK );
+
+	if ( nsldapi_build_search_req( ld, ludp->lud_dn, ludp->lud_scope,
+	    ludp->lud_filter, ludp->lud_attrs, attrsonly, NULL, NULL,
+	    -1, -1, msgid, &ber ) != LDAP_SUCCESS ) {
+		return( -1 );
+	}
+
+	err = 0;
+
+	if ( ludp->lud_host == NULL ) {
+		host = ld->ld_defhost;
+	} else {
+		host = ludp->lud_host;
+	}
+
+	if (( srv = (LDAPServer *)NSLDAPI_CALLOC( 1, sizeof( LDAPServer )))
+	    == NULL || ( host != NULL &&
+	    ( srv->lsrv_host = nsldapi_strdup( host )) == NULL )) {
+		if ( srv != NULL ) {
+			NSLDAPI_FREE( srv );
+		}
+		LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+		err = -1;
+	} else {
+		if ( ludp->lud_port != 0 ) {
+			/* URL includes a port - use it */
+			 srv->lsrv_port = ludp->lud_port;
+		} else if ( ludp->lud_host == NULL ) {
+			/* URL has no port or host - use port from ld */
+			srv->lsrv_port = ld->ld_defport;
+		} else if (( ludp->lud_options & LDAP_URL_OPT_SECURE ) == 0 ) {
+			/* ldap URL has a host but no port - use std. port */
+			srv->lsrv_port = LDAP_PORT;
+		} else {
+			/* ldaps URL has a host but no port - use std. port */
+			srv->lsrv_port = LDAPS_PORT;
+		}
+	}
+
+	if (( ludp->lud_options & LDAP_URL_OPT_SECURE ) != 0 ) {
+		srv->lsrv_options |= LDAP_SRV_OPT_SECURE;
+	}
+
+	if ( err != 0 ) {
+		ber_free( ber, 1 );
+	} else {
+		err = nsldapi_send_server_request( ld, ber, msgid, NULL, srv,
+		    NULL, NULL, 1 );
+	}
+
+	ldap_free_urldesc( ludp );
+	return( err );
+}
+
+
+int
+LDAP_CALL
+ldap_url_search_st( LDAP *ld, const char *url, int attrsonly,
+	struct timeval *timeout, LDAPMessage **res )
+{
+	int	msgid;
+
+	/*
+	 * It is an error to pass in a zero'd timeval.
+	 */
+	if ( timeout != NULL && timeout->tv_sec == 0 &&
+	    timeout->tv_usec == 0 ) {
+		if ( ld != NULL ) {
+			LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+		}
+		if ( res != NULL ) {
+			*res = NULL;
+		}
+                return( LDAP_PARAM_ERROR );
+        }
+
+	if (( msgid = ldap_url_search( ld, url, attrsonly )) == -1 ) {
+		return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+	}
+
+	if ( ldap_result( ld, msgid, 1, timeout, res ) == -1 ) {
+		return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+	}
+
+	if ( LDAP_GET_LDERRNO( ld, NULL, NULL ) == LDAP_TIMEOUT ) {
+		(void) ldap_abandon( ld, msgid );
+		LDAP_SET_LDERRNO( ld, LDAP_TIMEOUT, NULL, NULL );
+		return( LDAP_TIMEOUT );
+	}
+
+	return( ldap_result2error( ld, *res, 0 ));
+}
+
+
+int
+LDAP_CALL
+ldap_url_search_s( LDAP *ld, const char *url, int attrsonly, LDAPMessage **res )
+{
+	int	msgid;
+
+	if (( msgid = ldap_url_search( ld, url, attrsonly )) == -1 ) {
+		return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+	}
+
+	if ( ldap_result( ld, msgid, 1, (struct timeval *)NULL, res ) == -1 ) {
+		return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+	}
+
+	return( ldap_result2error( ld, *res, 0 ));
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/userstatusctrl.c
@@ -0,0 +1,228 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Sun LDAP C SDK.
+ *
+ * The Initial Developer of the Original Code is Sun Microsystems, Inc.
+ *
+ * Portions created by Sun Microsystems, Inc are Copyright (C) 2005
+ * Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Contributor(s): abobrov@sun.com
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ldap-int.h"
+
+/* ldap_create_userstatus_control:
+
+   Parameters are  
+
+   ld              LDAP pointer to the desired connection 
+
+   ctl_iscritical  Indicates whether the control is critical of not. If
+                   this field is non-zero, the operation will only be car-
+                   ried out if the control is recognized by the server
+                   and/or client
+
+   ctrlp           the address of a place to put the constructed control 
+*/
+
+int
+LDAP_CALL
+ldap_create_userstatus_control ( 	
+									LDAP *ld, 
+									const char ctl_iscritical,
+									LDAPControl **ctrlp   
+																)
+{
+	int rc;
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		return( LDAP_PARAM_ERROR );
+	}
+
+	if ( ctrlp == NULL ) {
+		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+		return ( LDAP_PARAM_ERROR );
+	}
+
+	rc = nsldapi_build_control( LDAP_CONTROL_ACCOUNT_USABLE, 
+								NULL, 0, ctl_iscritical, ctrlp );
+
+	LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+	return( rc );
+}
+
+/* ldap_parse_userstatus_control:
+
+   Parameters are  
+
+   ld              LDAP pointer to the desired connection 
+
+   ctrlp           An array of controls obtained from calling  
+                   ldap_parse_result on the set of results 
+                   returned by the server     
+
+   us              the address of struct LDAPuserstatus
+                   to parse control results to 
+*/
+
+int
+LDAP_CALL
+ldap_parse_userstatus_control ( 	
+									LDAP *ld, 
+									LDAPControl **ctrlp,  
+									LDAPuserstatus *us
+															)
+{
+	BerElement *ber = NULL;
+	int			i, foundUSControl;
+	LDAPControl *USCtrlp = NULL;
+	ber_tag_t	tag;
+
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) || us == NULL ) {
+	    return( LDAP_PARAM_ERROR );
+	}
+
+	/* find the control in the list of controls if it exists */
+	if ( ctrlp == NULL ) {
+		LDAP_SET_LDERRNO( ld, LDAP_CONTROL_NOT_FOUND, NULL, NULL );
+		return ( LDAP_CONTROL_NOT_FOUND );
+	} 
+	foundUSControl = 0;
+	for ( i = 0; (( ctrlp[i] != NULL ) && ( !foundUSControl )); i++ ) {
+		foundUSControl = !strcmp( ctrlp[i]->ldctl_oid, LDAP_CONTROL_ACCOUNT_USABLE );
+	}
+	if ( !foundUSControl ) {
+		LDAP_SET_LDERRNO( ld, LDAP_CONTROL_NOT_FOUND, NULL, NULL );
+		return ( LDAP_CONTROL_NOT_FOUND );
+	} else {
+		/* let local var point to the control */
+		USCtrlp = ctrlp[i-1];			
+	}
+
+	/*  allocate a Ber element with the contents of the control's struct berval */
+	if ( ( ber = ber_init( &USCtrlp->ldctl_value ) ) == NULL ) {
+		LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+		return( LDAP_NO_MEMORY );
+	}
+
+	memset( us, 0, sizeof(struct LDAPuserstatus) );
+
+    /*
+     * The control value should look like this:
+     *
+	 *	ACCOUNT_USABLE_RESPONSE::= CHOICE {
+	 * 		is_available		[0] INTEGER, ** seconds before expiration **
+	 *		is_not_available	[1] More_info
+	 *	}
+	 *	More_info::= SEQUENCE {
+	 *		inactive				[0] BOOLEAN DEFAULT FALSE,    
+	 *		reset					[1] BOOLEAN DEFAULT FALSE,    
+	 *		expired					[2] BOOLEAN DEFAULT FALSE,    
+	 *		remaining_grace			[3] INTEGER OPTIONAL,
+	 *		seconds_before_unlock	[4] INTEGER OPTIONAL
+	 *	}
+	 */
+
+	if ( ( ber_scanf( ber, "t", &tag ) ) == LBER_ERROR ) {
+		LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
+		ber_free( ber, 1 );
+		return( LDAP_DECODING_ERROR );
+	}
+
+    tag = (( tag & LBER_CONSTRUCTED ) == LBER_CONSTRUCTED ) ? 1 : 0;
+
+	if ( !tag ) {
+		us->us_available = 1;
+		if ( ber_scanf( ber, "i", &us->us_expire ) == LBER_ERROR ) {
+			LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
+			ber_free( ber, 1 );
+			return( LDAP_DECODING_ERROR );
+		}
+	} else {
+		us->us_available = 0;
+		tag = 0;
+		if ( ( ber_scanf( ber, "{t", &tag ) ) == LBER_ERROR ) {
+			LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
+			ber_free( ber, 1 );
+			return( LDAP_DECODING_ERROR );
+		}
+        while ( tag != LBER_ERROR && tag != LBER_END_OF_SEQORSET ) {
+            tag = tag & (~LBER_CLASS_CONTEXT);
+            switch (tag)
+			{
+				case 0:
+                    if ( ber_scanf( ber, "b", &us->us_inactive ) == LBER_ERROR ) {
+                        LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
+                        ber_free( ber, 1 );
+                        return( LDAP_DECODING_ERROR );
+                    }
+                    us->us_inactive = ( us->us_inactive != 0 ) ? 1 : 0;
+                    break;
+				case 1:
+                    if ( ber_scanf( ber, "b", &us->us_reset ) == LBER_ERROR ) {
+                        LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
+                        ber_free( ber, 1 );
+                        return( LDAP_DECODING_ERROR );
+                    }
+                    us->us_reset = ( us->us_reset != 0 ) ? 1 : 0;
+                    break;
+				case 2:
+                    if ( ber_scanf( ber, "b", &us->us_expired ) == LBER_ERROR ) {
+                        LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
+                        ber_free( ber, 1 );
+                        return( LDAP_DECODING_ERROR );
+                    }
+                    us->us_expired = ( us->us_expired != 0 ) ? 1 : 0;
+                    break;
+                case 3:
+                    if ( ber_scanf( ber, "i", &us->us_remaining ) == LBER_ERROR ) {
+                        LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
+                        ber_free( ber, 1 );
+                        return( LDAP_DECODING_ERROR );
+                    }
+                    break;
+                case 4:
+                    if ( ber_scanf( ber, "i", &us->us_seconds ) == LBER_ERROR ) {
+                        LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
+                        ber_free( ber, 1 );
+                        return( LDAP_DECODING_ERROR );
+                    }
+                    break;
+                default:
+                    LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
+                    ber_free( ber, 1 );
+                    return( LDAP_DECODING_ERROR );
+            }
+            ber_scanf( ber, "t", &tag );
+        }
+	}
+
+	/* the ber encoding is no longer needed */
+	ber_free( ber, 1 );
+	return( LDAP_SUCCESS );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/utf8.c
@@ -0,0 +1,282 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+/* uft8.c - misc. utf8 "string" functions. */
+#include "ldap-int.h"
+
+static char UTF8len[64]
+= {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+   2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 5, 6};
+
+int
+LDAP_CALL
+ldap_utf8len (const char* s)
+     /* Return the number of char's in the character at *s. */
+{
+    return ldap_utf8next((char*)s) - s;
+}
+
+char*
+LDAP_CALL
+ldap_utf8next (char* s)
+     /* Return a pointer to the character immediately following *s.
+	Handle any valid UTF-8 character, including '\0' and ASCII.
+	Try to handle a misaligned pointer or a malformed character.
+     */
+{
+    register unsigned char* next = (unsigned char*)s;
+    switch (UTF8len [(*next >> 2) & 0x3F]) {
+      case 0: /* erroneous: s points to the middle of a character. */
+      case 6: if ((*++next & 0xC0) != 0x80) break;
+      case 5: if ((*++next & 0xC0) != 0x80) break;
+      case 4: if ((*++next & 0xC0) != 0x80) break;
+      case 3: if ((*++next & 0xC0) != 0x80) break;
+      case 2: if ((*++next & 0xC0) != 0x80) break;
+      case 1: ++next;
+    }
+    return (char*) next;
+}
+
+char*
+LDAP_CALL
+ldap_utf8prev (char* s)
+     /* Return a pointer to the character immediately preceding *s.
+	Handle any valid UTF-8 character, including '\0' and ASCII.
+	Try to handle a misaligned pointer or a malformed character.
+     */
+{
+    register unsigned char* prev = (unsigned char*)s;
+    unsigned char* limit = prev - 6;
+    while (((*--prev & 0xC0) == 0x80) && (prev != limit)) {
+    	;
+    }
+    return (char*) prev;
+}
+
+int
+LDAP_CALL
+ldap_utf8copy (char* dst, const char* src)
+     /* Copy a character from src to dst; return the number of char's copied.
+	Handle any valid UTF-8 character, including '\0' and ASCII.
+	Try to handle a misaligned pointer or a malformed character.
+     */
+{
+    register const unsigned char* s = (const unsigned char*)src;
+    switch (UTF8len [(*s >> 2) & 0x3F]) {
+      case 0: /* erroneous: s points to the middle of a character. */
+      case 6: *dst++ = *s++; if ((*s & 0xC0) != 0x80) break;
+      case 5: *dst++ = *s++; if ((*s & 0xC0) != 0x80) break;
+      case 4: *dst++ = *s++; if ((*s & 0xC0) != 0x80) break;
+      case 3: *dst++ = *s++; if ((*s & 0xC0) != 0x80) break;
+      case 2: *dst++ = *s++; if ((*s & 0xC0) != 0x80) break;
+      case 1: *dst   = *s++;
+    }
+    return s - (const unsigned char*)src;
+}
+
+size_t
+LDAP_CALL
+ldap_utf8characters (const char* src)
+     /* Return the number of UTF-8 characters in the 0-terminated array s. */
+{
+    register char* s = (char*)src;
+    size_t n;
+    for (n = 0; *s; LDAP_UTF8INC(s)) ++n;
+    return n;
+}
+
+unsigned long LDAP_CALL
+ldap_utf8getcc( const char** src )
+{
+    register unsigned long c = 0;
+    register const unsigned char* s = (const unsigned char*)*src;
+    switch (UTF8len [(*s >> 2) & 0x3F]) {
+      case 0: /* erroneous: s points to the middle of a character. */
+	      c = (*s++) & 0x3F; goto more5;
+      case 1: c = (*s++); break;
+      case 2: c = (*s++) & 0x1F; goto more1;
+      case 3: c = (*s++) & 0x0F; goto more2;
+      case 4: c = (*s++) & 0x07; goto more3;
+      case 5: c = (*s++) & 0x03; goto more4;
+      case 6: c = (*s++) & 0x01; goto more5;
+      more5: if ((*s & 0xC0) != 0x80) break; c = (c << 6) | ((*s++) & 0x3F);
+      more4: if ((*s & 0xC0) != 0x80) break; c = (c << 6) | ((*s++) & 0x3F);
+      more3: if ((*s & 0xC0) != 0x80) break; c = (c << 6) | ((*s++) & 0x3F);
+      more2: if ((*s & 0xC0) != 0x80) break; c = (c << 6) | ((*s++) & 0x3F);
+      more1: if ((*s & 0xC0) != 0x80) break; c = (c << 6) | ((*s++) & 0x3F);
+	break;
+    }
+    *src = (const char*)s;
+    return c;
+}
+
+char*
+LDAP_CALL
+ldap_utf8strtok_r( char* sp, const char* brk, char** next)
+{
+    const char *bp;
+    unsigned long sc, bc;
+    char *tok;
+
+    if (sp == NULL && (sp = *next) == NULL)
+      return NULL;
+
+    /* Skip leading delimiters; roughly, sp += strspn(sp, brk) */
+  cont:
+    sc = LDAP_UTF8GETC(sp);
+    for (bp = brk; (bc = LDAP_UTF8GETCC(bp)) != 0;) {
+	if (sc == bc)
+	  goto cont;
+    }
+
+    if (sc == 0) { /* no non-delimiter characters */
+	*next = NULL;
+	return NULL;
+    }
+    tok = LDAP_UTF8PREV(sp);
+
+    /* Scan token; roughly, sp += strcspn(sp, brk)
+     * Note that brk must be 0-terminated; we stop if we see that, too.
+     */
+    while (1) {
+	sc = LDAP_UTF8GETC(sp);
+	bp = brk;
+	do {
+	    if ((bc = LDAP_UTF8GETCC(bp)) == sc) {
+		if (sc == 0) {
+		    *next = NULL;
+		} else {
+		    *next = sp;
+		    *(LDAP_UTF8PREV(sp)) = 0;
+		}
+		return tok;
+	    }
+	} while (bc != 0);
+    }
+    /* NOTREACHED */
+}
+
+int
+LDAP_CALL
+ldap_utf8isalnum( char* s )
+{
+    register unsigned char c = *(unsigned char*)s;
+    if (0x80 & c) return 0;
+    if (c >= 'A' && c <= 'Z') return 1;
+    if (c >= 'a' && c <= 'z') return 1;
+    if (c >= '0' && c <= '9') return 1;
+    return 0;
+}
+
+int
+LDAP_CALL
+ldap_utf8isalpha( char* s )
+{
+    register unsigned char c = *(unsigned char*)s;
+    if (0x80 & c) return 0;
+    if (c >= 'A' && c <= 'Z') return 1;
+    if (c >= 'a' && c <= 'z') return 1;
+    return 0;
+}
+
+int
+LDAP_CALL
+ldap_utf8isdigit( char* s )
+{
+    register unsigned char c = *(unsigned char*)s;
+    if (0x80 & c) return 0;
+    if (c >= '0' && c <= '9') return 1;
+    return 0;
+}
+
+int
+LDAP_CALL
+ldap_utf8isxdigit( char* s )
+{
+    register unsigned char c = *(unsigned char*)s;
+    if (0x80 & c) return 0;
+    if (c >= '0' && c <= '9') return 1;
+    if (c >= 'A' && c <= 'F') return 1;
+    if (c >= 'a' && c <= 'f') return 1;
+    return 0;
+}
+
+int
+LDAP_CALL
+ldap_utf8isspace( char* s )
+{
+    register unsigned char *c = (unsigned char*)s;
+    int len = ldap_utf8len(s);
+
+    if (len == 0) {
+	return 0;
+    } else if (len == 1) {
+	switch (*c) {
+	    case 0x09:
+	    case 0x0A:
+	    case 0x0B:
+	    case 0x0C:
+	    case 0x0D:
+	    case 0x20:
+		return 1;
+	    default:
+		return 0;
+	}
+    } else if (len == 2) {
+	if (*c == 0xc2) {
+		return *(c+1) == 0x80;
+	}
+    } else if (len == 3) {
+	if (*c == 0xE2) {
+	    c++;
+	    if (*c == 0x80) {
+		c++;
+		return (*c>=0x80 && *c<=0x8a);
+	    }
+	} else if (*c == 0xE3) {
+	    return (*(c+1)==0x80) && (*(c+2)==0x80);
+	} else if (*c==0xEF) {
+	    return (*(c+1)==0xBB) && (*(c+2)==0xBF);
+	}
+	return 0;
+    }
+
+    /* should never reach here */
+    return 0;
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/vlistctrl.c
@@ -0,0 +1,259 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+/* vlistctrl.c - virtual list control implementation. */
+#include "ldap-int.h"
+
+
+
+/*
+ * function to create a VirtualListViewRequest control that can be passed
+ * to ldap_search_ext() or ldap_search_ext_s().  *ctrlp will be set to a
+ * freshly allocated LDAPControl structure.  Returns an LDAP error code
+ * (LDAP_SUCCESS if all goes well).
+ * 
+ *  Parameters
+ *   ld              LDAP pointer to the desired connection 
+ *
+ *   ldvlistp        the control structure.
+ *
+ *   ctrlp           the address of a place to put the constructed control 
+
+  The controlValue is an OCTET STRING
+  whose value is the BER-encoding of the following SEQUENCE:
+  
+       VirtualListViewRequest ::= SEQUENCE {
+               beforeCount    INTEGER (0 .. maxInt),
+               afterCount     INTEGER (0 .. maxInt),
+               CHOICE {
+                       byIndex [0] SEQUENCE {
+                       index           INTEGER (0 .. maxInt),
+                       contentCount    INTEGER (0 .. maxInt) }
+                       byValue [1] greaterThanOrEqual assertionValue }
+  
+  beforeCount indicates how many  entries  before  the  target  entry  the
+  client  wants  the  server  to  send. afterCount indicates the number of
+  entries after the target entry the client  wants  the  server  to  send.
+  index  and contentCount identify the target entry
+  greaterThanOrEqual  is  an  attribute  assertion  value  defined  in
+  [LDAPv3].  If  present, the value supplied in greaterThanOrEqual is used
+  to determine the target entry by  comparison  with  the  values  of  the
+  attribute  specified as the primary sort key. The first list entry who's
+  value is no less than the supplied value is the target entry.
+
+ */
+
+int 
+LDAP_CALL
+ldap_create_virtuallist_control( 
+    LDAP *ld, 
+    LDAPVirtualList *ldvlistp,
+    LDAPControl **ctrlp 
+)
+{
+    BerElement *ber;
+    int rc;
+    
+    if (!NSLDAPI_VALID_LDAP_POINTER( ld )) {
+	return( LDAP_PARAM_ERROR );
+    }
+
+
+    if ( NULL == ctrlp || NULL == ldvlistp ) {
+        LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+        return ( LDAP_PARAM_ERROR );
+    }
+
+    /* create a ber package to hold the controlValue */
+    if ( LDAP_SUCCESS != nsldapi_alloc_ber_with_options( ld, &ber )  ) 
+    {
+        LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+        return( LDAP_NO_MEMORY );
+    }
+
+    if ( LBER_ERROR == ber_printf( ber, 
+                                   "{ii", 
+                                   ldvlistp->ldvlist_before_count,
+                                   ldvlistp->ldvlist_after_count )) 
+				    /* XXX lossy casts */
+    {
+        LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
+        ber_free( ber, 1 );
+        return( LDAP_ENCODING_ERROR );
+    }
+
+    if (NULL == ldvlistp->ldvlist_attrvalue)
+    {
+        if ( LBER_ERROR == ber_printf( ber, 
+                                       "t{ii}}", 
+				       LDAP_TAG_VLV_BY_INDEX,
+                                       ldvlistp->ldvlist_index, 
+                                       ldvlistp->ldvlist_size ) ) 
+				       /* XXX lossy casts */
+        {
+            LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
+            ber_free( ber, 1 );
+            return( LDAP_ENCODING_ERROR );
+        }
+    } 
+    else 
+    {
+        if ( LBER_ERROR == ber_printf( ber, 
+                                      "to}", 
+				       LDAP_TAG_VLV_BY_VALUE,
+                                      ldvlistp->ldvlist_attrvalue,
+				       (int)strlen( ldvlistp->ldvlist_attrvalue )) ) {
+            LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
+            ber_free( ber, 1 );
+            return( LDAP_ENCODING_ERROR );
+        }
+    }
+
+
+    rc = nsldapi_build_control( LDAP_CONTROL_VLVREQUEST , 
+                                ber, 
+                                1,
+                                1, 
+                                ctrlp );
+
+    LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+    return( rc );
+
+}
+
+
+/*
+ * function to find and parse a VirtualListViewResponse control contained in
+ * "ctrls"  *target_posp, *list_sizep, and *errcodep are set based on its
+ * contents.  Returns an LDAP error code that indicates whether the parsing
+ * itself was successful (LDAP_SUCCESS if all goes well).
+
+  The controlValue is an OCTET STRING, whose value
+  is the BER encoding of a value of the following SEQUENCE:
+  
+       VirtualListViewResponse ::= SEQUENCE {
+               targetPosition    INTEGER (0 .. maxInt),
+               contentCount     INTEGER (0 .. maxInt),
+               virtualListViewResult ENUMERATED {
+                       success (0),
+                       operatonsError (1),
+                       unwillingToPerform (53),
+                       insufficientAccessRights (50),
+                       busy (51),
+                       timeLimitExceeded (3),
+                       adminLimitExceeded (11),
+                       sortControlMissing (60),
+                       indexRangeError (61),
+                       other (80) }  }
+
+ */
+int 
+LDAP_CALL
+ldap_parse_virtuallist_control
+( 
+    LDAP *ld, 
+    LDAPControl **ctrls,
+    ber_int_t *target_posp, 
+    ber_int_t *list_sizep, 
+    int *errcodep
+)
+{
+    BerElement		*ber;
+    int			i, foundListControl;
+    ber_int_t		errcode;
+    LDAPControl		*listCtrlp;
+    ber_int_t	target_pos, list_size;
+
+    if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+        return( LDAP_PARAM_ERROR );
+    }
+
+    /* only ldapv3 or higher can do virtual lists. */
+    if ( NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION3 ) {
+        LDAP_SET_LDERRNO( ld, LDAP_NOT_SUPPORTED, NULL, NULL );
+        return( LDAP_NOT_SUPPORTED );
+    }
+
+    /* find the listControl in the list of controls if it exists */
+    if ( ctrls == NULL ) {
+        LDAP_SET_LDERRNO( ld, LDAP_CONTROL_NOT_FOUND, NULL, NULL );
+        return ( LDAP_CONTROL_NOT_FOUND );
+    } 
+    
+    foundListControl = 0;
+    for ( i = 0; (( ctrls[i] != NULL ) && ( !foundListControl )); i++ ) {
+        foundListControl = !strcmp( ctrls[i]->ldctl_oid, 
+                                    LDAP_CONTROL_VLVRESPONSE );
+    }
+    if ( !foundListControl ) {
+        LDAP_SET_LDERRNO( ld, LDAP_CONTROL_NOT_FOUND, NULL, NULL );
+        return ( LDAP_CONTROL_NOT_FOUND );
+    } else {
+        /* let local var point to the listControl */
+        listCtrlp = ctrls[i-1];                 
+    }
+
+    /*  allocate a Ber element with the contents of the list_control's struct berval */
+    if ( ( ber = ber_init( &listCtrlp->ldctl_value ) ) == NULL ) {
+        LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+        return( LDAP_NO_MEMORY );
+    }           
+
+    /* decode the result from the Berelement */
+    if (  LBER_ERROR == ber_scanf( ber, "{iie}", &target_pos, &list_size,
+	    &errcode ) ) {
+        LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
+        ber_free( ber, 1 );
+        return( LDAP_DECODING_ERROR );
+    }
+
+    if ( target_posp != NULL ) {
+        *target_posp = target_pos;
+    }
+    if ( list_sizep != NULL ) {
+        *list_sizep = list_size;
+    }
+    if ( errcodep != NULL ) {
+        *errcodep = (int)errcode;
+    }
+
+    /* the ber encoding is no longer needed */
+    ber_free(ber,1);
+
+    return(LDAP_SUCCESS);
+
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldap/whoami.c
@@ -0,0 +1,130 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Sun LDAP C SDK.
+ *
+ * The Initial Developer of the Original Code is Sun Microsystems, Inc.
+ *
+ * Portions created by Sun Microsystems, Inc are Copyright (C) 2005
+ * Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Contributor(s): abobrov@sun.com
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ldap-int.h"
+
+/* ldap_whoami */
+int
+LDAP_CALL
+ldap_whoami ( 	
+				LDAP          *ld, 
+				LDAPControl   **serverctrls,
+				LDAPControl   **clientctrls,
+				int           *msgidp
+												)
+{
+	int				rc;
+	struct berval   *requestdata = NULL;
+	
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+		return( LDAP_PARAM_ERROR );
+	}
+	
+	rc = ldap_extended_operation( ld, LDAP_EXOP_WHO_AM_I, requestdata, 
+									serverctrls, clientctrls, msgidp );
+	
+	return( rc );
+}
+
+/* ldap_parse_whoami */
+int
+LDAP_CALL
+ldap_parse_whoami ( 	
+						LDAP			*ld, 
+						LDAPMessage		*result,
+						struct berval	**authzid
+													)
+{	
+	int				rc;
+	char			*retoidp = NULL;
+	
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+		return( LDAP_PARAM_ERROR );
+	}
+	if ( !result ) {
+		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+		return( LDAP_PARAM_ERROR );
+	}
+	
+	*authzid = NULL;
+	
+	rc = ldap_parse_extended_result( ld, result, &retoidp, authzid, 0 );
+	
+	if ( rc != LDAP_SUCCESS ) {
+		return( rc );
+    }
+	
+	ldap_memfree( retoidp );
+	return( LDAP_SUCCESS );
+}
+
+/* ldap_whoami_s */
+int
+LDAP_CALL
+ldap_whoami_s ( 	
+				LDAP          *ld,
+				struct berval **authzid,
+				LDAPControl   **serverctrls,
+				LDAPControl   **clientctrls
+												)
+{
+	int			rc;
+	int			msgid;
+	LDAPMessage	*result = NULL;
+	
+	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
+		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+		return( LDAP_PARAM_ERROR );
+	}	
+	
+	rc = ldap_whoami( ld, serverctrls, clientctrls, &msgid );
+	if ( rc != LDAP_SUCCESS ) {
+		return( rc );
+	}
+	
+	rc = ldap_result( ld, msgid, LDAP_MSG_ALL, NULL, &result );
+	if ( rc == -1 ) {
+		return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
+	}
+
+	rc = ldap_parse_whoami( ld, result, authzid );
+	
+	ldap_msgfree( result );
+	
+	return( rc );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldif/Makefile.in
@@ -0,0 +1,166 @@
+# 
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+# 
+# The contents of this file are subject to the Mozilla Public License Version 
+# 1.1 (the "License"); you may not use this file except in compliance with 
+# the License. You may obtain a copy of the License at 
+# http://www.mozilla.org/MPL/
+# 
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+# 
+# The Original Code is Mozilla Communicator client code, released
+# March 31, 1998.
+# 
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 1998-1999
+# the Initial Developer. All Rights Reserved.
+# 
+# Contributor(s):
+# 
+# Alternatively, the contents of this file may be used under the terms of
+# either of the GNU General Public License Version 2 or later (the "GPL"),
+# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+# 
+# ***** END LICENSE BLOCK ***** 
+
+MOD_DEPTH = ../../..
+srcdir = @srcdir@
+topsrcdir = @top_srcdir@
+
+include $(MOD_DEPTH)/config/autoconf.mk
+include $(topsrcdir)/build.mk
+
+SRCS		= line64.c
+
+RELEASE_LIBS    = $(SHARED_LIBRARY) $(DLLLDIF)
+
+REALOBJS	= $(SRCS:.c=.$(OBJ_SUFFIX))
+OBJS		= $(addprefix $(OBJDIR_NAME)/, $(REALOBJS))
+
+HDIR		= $(topsrcdir)/ldap/include
+
+LIBLDIF		= $(addprefix $(OBJDIR_NAME)/, $(LIB_PREFIX)$(LDIF_LIBNAME).$(LIB_SUFFIX))
+DLLLDIF         = $(addprefix $(OBJDIR_NAME)/, $(LIB_PREFIX)$(LDIF_LIBNAME).$(DLL_SUFFIX))
+
+INSTALLDIR      = $(DIST)/$(OBJDIR_NAME)
+
+include $(topsrcdir)/config/rules.mk
+
+GARBAGE 	+= $(LIBLDIF) $(DLLLDIF)
+
+LOCAL_INCLUDES  = -I$(PUBLIC)/nspr
+INCLUDES	+= -I$(HDIR) -I$(INSTALLDIR)/include -I$(DIST)/include
+DEFINES		+= $(DEFS)
+
+PLATFORMCFLAGS	= -DUSE_WAITPID -DNEEDPROTOS
+PLATFORMLIBS	=
+THREADS		=
+THREADSLIB	=
+
+ifeq ($(OS_ARCH), AIX)
+PLATFORMLIBS	+= -ldl -brtl -lpthreads -lc_r -lm
+endif
+
+#
+# shared library symbol export definitions
+#
+ifeq ($(USE_DLL_EXPORTS_FILE), 1)
+ifeq ($(OS_ARCH), WINNT)
+GENEXPORTS=cmd /c  $(PERL) $(topsrcdir)/ldap/build/genexports.pl
+else
+GENEXPORTS=$(PERL) $(topsrcdir)/ldap/build/genexports.pl
+endif
+
+# variable definitions for exported symbols
+ifeq ($(OS_ARCH), WINNT)
+        LDIF_EXPORT_DEFS= $(WIN_TOP_SRC)/ldap/libraries/msdos/winsock/nsldif32.def
+else
+ifeq ($(OS_ARCH), OS2)
+        LDIF_EXPORT_DEFS= $(OBJDIR_NAME)/libldif.def
+else
+        LDIF_EXPORT_DEFS= $(OBJDIR_NAME)/libldif.exp
+endif
+GARBAGE += $(LDIF_EXPORT_DEFS)
+endif
+
+LDIF_EXPORT_FLAGS=$(addprefix $(DLLEXPORTS_PREFIX), $(LDIF_EXPORT_DEFS))
+
+GENEXPARGS=$(BUILD_DEBUG) $(LDIFVERS_SUFFIX) $(LDIFVERS)
+endif # USE_DLL_EXPORTS_FILE
+
+
+###########################################################################
+
+ifeq ($(USE_DLL_EXPORTS_FILE), 1)
+# recursive gmake rule to create exported symbols file
+$(LDIF_EXPORT_DEFS):: $(srcdir)/../libldif.ex
+ifeq ($(OS_ARCH), WINNT)
+	$(GENEXPORTS) Win32 $(srcdir)/../msdos/winsock/nsldif32.tdf $< $(GENEXPARGS) > $@
+else
+ifeq ($(OS_ARCH), OS2)
+	echo LIBRARY $(LDIF_LIBNAME) INITINSTANCE TERMINSTANCE > $@
+	echo PROTMODE >> $@
+	echo CODE    LOADONCALL MOVEABLE DISCARDABLE >> $@
+	echo DATA    PRELOAD MOVEABLE MULTIPLE NONSHARED >> $@
+	echo EXPORTS >> $@
+	$(GENEXPORTS) $(OS_ARCH) Standard $< $(GENEXPARGS) >> $@
+else
+	$(GENEXPORTS) $(OS_ARCH) Standard $< $(GENEXPARGS) > $@
+endif
+endif
+endif # USE_DLL_EXPORTS_FILE
+
+versiont.c:	Makefile.client Version.c
+	@$(RM) $@
+	@(u="$${USER-root}" v="$(shell cat ../../build/version)" d="$(shell pwd)" \
+	h="$(shell hostname)" t="$(shell date)"; $(SED) -e "s|%WHEN%|$${t}|" \
+	-e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
+	-e "s|%VERSION%|$${v}|" \
+	< Version.c > $@)
+
+export::    $(OBJDEST) $(LIBDIR) $(OBJS) $(LIBLDIF)
+
+$(LIBDIR):
+	$(MKDIR) $(LIBDIR)
+
+$(LIBLDIF): $(OBJS) $(LIBDIR)
+	@echo ======= making $(LIBLDIF)
+
+	$(LINK_LIB)
+
+$(DLLLDIF): $(OBJS) $(LIBDIR) $(LDIF_EXPORT_DEFS)
+	@echo ======= making $(DLLLDIF)
+
+ifdef SO_FILES_TO_REMOVE
+	-$(RM) $(SO_FILES_TO_REMOVE)
+endif
+
+	$(LINK_DLL) $(LDIF_EXPORT_FLAGS) $(PLATFORMLIBS) $(EXTRA_LIBS)
+
+
+veryclean:: clean
+
+$(OBJDEST):
+	$(MKDIR) $(OBJDEST)
+
+export::	$(DLLLDIF) $(LIBLDIF)
+	$(INSTALL) -m 444 $(LIBLDIF) $(dist_libdir)
+
+ifdef MKSHLIB
+	$(INSTALL) -m 444 $(LIBLDIF) $(dist_libdir)
+	$(INSTALL) -m 444 $(DLLLDIF) $(dist_libdir)
+	$(INSTALL) -m 444 $(DLLLDIF) $(dist_bindir)
+endif
new file mode 100755
--- /dev/null
+++ b/ldap/c-sdk/libraries/libldif/line64.c
@@ -0,0 +1,612 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+/* line64.c - routines for dealing with the slapd line format */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#ifndef macintosh
+#include <sys/types.h>
+#endif
+#ifdef _WIN32
+#include <windows.h>
+#elif !defined( macintosh )
+#include <sys/socket.h>
+#endif
+#include "ldaplog.h"
+#include "ldif.h"
+
+#ifndef isascii
+#define isascii( c )	(!((c) & ~0177))
+#endif
+
+#define RIGHT2			0x03
+#define RIGHT4			0x0f
+#define CONTINUED_LINE_MARKER	'\001'
+
+#define ISBLANK(c) (c == ' ' || c == '\t' || c == '\n') /* not "\r\v\f" */
+
+#define LDIF_OPT_ISSET( value, opt )	(((value) & (opt)) != 0 )
+
+static char nib2b64[0x40f] =
+        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static unsigned char b642nib[0x80] = {
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
+	0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
+	0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+	0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+	0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
+	0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+	0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+	0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
+	0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+static int ldif_base64_encode_internal( unsigned char *src, char *dst, int srclen,
+	int lenused, int wraplen );
+
+/*
+ * ldif_parse_line - takes a line of the form "type:[:] value" and splits it
+ * into components "type" and "value".  if a double colon separates type from
+ * value, then value is encoded in base 64, and parse_line un-decodes it
+ * (in place) before returning.
+ */
+
+int
+ldif_parse_line(
+    char	*line,
+    char	**type,
+    char	**value,
+    int		*vlen
+)
+{
+	char	*p, *s, *d;
+	int	b64;
+
+	/* skip any leading space */
+	while ( ISBLANK( *line ) ) {
+		line++;
+	}
+	*type = line;
+
+	for ( s = line; *s && *s != ':'; s++ )
+		;	/* NULL */
+	if ( *s == '\0' ) {
+
+		/* Comment-out while we address calling libldif from ns-back-ldbm
+			on NT. 1 of 3 */
+#if defined( _WIN32 )
+		/*
+#endif
+		 LDAPDebug( LDAP_DEBUG_PARSE, "ldif_parse_line: missing ':' "
+			"on line \"%s\"\n", line, 0, 0 ); 
+#if defined( _WIN32 )
+		*/
+#endif
+		return( -1 );
+	}
+
+	/* trim any space between type and : */
+	for ( p = s - 1; p > line && ISBLANK( *p ); p-- ) {
+		*p = '\0';
+	}
+	*s++ = '\0';
+
+	/* check for double : - indicates base 64 encoded value */
+	if ( *s == ':' ) {
+		s++;
+		b64 = 1;
+
+	/* single : - normally encoded value */
+	} else {
+		b64 = 0;
+	}
+
+	/* skip space between : and value */
+	while ( ISBLANK( *s ) ) {
+		s++;
+	}
+
+	/* 
+	 * If no value is present, return a zero-length string for
+	 * *value, with *vlen set to zero.
+	 */
+	if ( *s == '\0' ) {
+		*value = s;
+		*vlen = 0;
+		return( 0 );
+	}
+
+	/* check for continued line markers that should be deleted */
+	for ( p = s, d = s; *p; p++ ) {
+		if ( *p != CONTINUED_LINE_MARKER )
+			*d++ = *p;
+	}
+	*d = '\0';
+
+	*value = s;
+	if ( b64 ) {
+		if (( *vlen = ldif_base64_decode( s, (unsigned char *)s ))
+		    < 0 ) {
+			/* Comment-out while we address calling libldif from ns-back-ldbm
+				on NT. 3 of 3 */
+#if defined( _WIN32 )
+		/*
+#endif
+			 LDAPDebug( LDAP_DEBUG_ANY,
+			    "ldif_parse_line: invalid base 64 char on line \"%s\"\n",
+			    line, 0, 0 ); 
+#if defined( _WIN32 )
+		*/
+#endif
+			return( -1 );
+		}
+		s[ *vlen ] = '\0';
+	} else {
+		*vlen = (int) (d - s);
+	}
+
+	return( 0 );
+}
+
+
+/*
+ * ldif_base64_decode - take the BASE64-encoded characters in "src"
+ * (a zero-terminated string) and decode them into the the buffer "dst".
+ * "src" and "dst" can be the same if in-place decoding is desired.
+ * "dst" must be large enough to hold the decoded octets.  No more than
+ *	3 * strlen( src ) / 4 bytes will be produced.
+ * "dst" may contain zero octets anywhere within it, but it is not
+ *	zero-terminated by this function.
+ *
+ * The number of bytes copied to "dst" is returned if all goes well.
+ * -1 is returned if the BASE64 encoding in "src" is invalid.
+ */
+
+int
+ldif_base64_decode( char *src, unsigned char *dst )
+{
+	char		*p, *stop;
+	unsigned char	nib, *byte;
+	int		i, len;
+
+	stop = strchr( src, '\0' );
+	byte = dst;
+	for ( p = src, len = 0; p < stop; p += 4, len += 3 ) {
+		for ( i = 0; i < 4; i++ ) {
+			if ( p[i] != '=' && (p[i] & 0x80 ||
+			    b642nib[ p[i] & 0x7f ] > 0x3f) ) {
+				return( -1 );
+			}
+		}
+
+		/* first digit */
+		nib = b642nib[ p[0] & 0x7f ];
+		byte[0] = nib << 2;
+
+		/* second digit */
+		nib = b642nib[ p[1] & 0x7f ];
+		byte[0] |= nib >> 4;
+
+		/* third digit */
+		if ( p[2] == '=' ) {
+			len += 1;
+			break;
+		}
+		byte[1] = (nib & RIGHT4) << 4;
+		nib = b642nib[ p[2] & 0x7f ];
+		byte[1] |= nib >> 2;
+
+		/* fourth digit */
+		if ( p[3] == '=' ) {
+			len += 2;
+			break;
+		}
+		byte[2] = (nib & RIGHT2) << 6;
+		nib = b642nib[ p[3] & 0x7f ];
+		byte[2] |= nib;
+
+		byte += 3;
+	}
+
+	return( len );
+}
+
+/*
+ * ldif_getline - return the next "line" (minus newline) of input from a
+ * string buffer of lines separated by newlines, terminated by \n\n
+ * or \0.  this routine handles continued lines, bundling them into
+ * a single big line before returning.  if a line begins with a white
+ * space character, it is a continuation of the previous line. the white
+ * space character (nb: only one char), and preceeding newline are changed
+ * into CONTINUED_LINE_MARKER chars, to be deleted later by the
+ * ldif_parse_line() routine above.
+ *
+ * it takes a pointer to a pointer to the buffer on the first call,
+ * which it updates and must be supplied on subsequent calls.
+ *
+ * XXX need to update this function to also support <CR><LF> as EOL.
+ * XXX supports <CR><LF> as of 07/29/1998 (richm)
+ */
+
+char *
+ldif_getline( char **next )
+{
+	char	*l;
+	char	c;
+	char	*p;
+
+	if ( *next == NULL || **next == '\n' || **next == '\0' ) {
+		return( NULL );
+	}
+
+	while ( **next == '#' ) {	/* skip comment lines */
+		if (( *next = strchr( *next, '\n' )) == NULL ) {
+			return( NULL );
+		}
+		(*next)++;
+	}
+
+	l = *next;
+	while ( (*next = strchr( *next, '\n' )) != NULL ) {
+		p = *next - 1; /* pointer to character previous to the newline */
+		c = *(*next + 1); /* character after the newline */
+		if ( ISBLANK( c ) && c != '\n' ) {
+			/* DOS EOL is \r\n, so if the character before */
+			/* the \n is \r, continue it too */
+			if (*p == '\r')
+				*p = CONTINUED_LINE_MARKER;
+			**next = CONTINUED_LINE_MARKER;
+			*(*next+1) = CONTINUED_LINE_MARKER;
+		} else {
+			/* DOS EOL is \r\n, so if the character before */
+			/* the \n is \r, null it too */
+			if (*p == '\r')
+				*p = '\0';
+			*(*next)++ = '\0';
+			break;
+		}
+		(*next)++;
+	}
+
+	return( l );
+}
+
+
+#define LDIF_SAFE_CHAR( c )		( (c) != '\r' && (c) != '\n' )
+#define LDIF_CONSERVATIVE_CHAR( c )	( LDIF_SAFE_CHAR(c) && isascii((c)) \
+					 && ( isprint((c)) || (c) == '\t' ))
+#define LDIF_SAFE_INITCHAR( c )		( LDIF_SAFE_CHAR(c) && (c) != ':' \
+					 && (c) != ' ' && (c) != '<' )
+#define LDIF_CONSERVATIVE_INITCHAR( c ) ( LDIF_SAFE_INITCHAR( c ) && \
+					 ! ( isascii((c)) && isspace((c))))
+#define LDIF_CONSERVATIVE_FINALCHAR( c ) ( (c) != ' ' )
+
+
+void
+ldif_put_type_and_value_with_options( char **out, char *t, char *val,
+	int vlen, unsigned long options )
+{
+	unsigned char	*p, *byte, *stop;
+	char		*save;
+	int		b64, len, savelen, wraplen;
+	len = 0;
+
+	if ( LDIF_OPT_ISSET( options, LDIF_OPT_NOWRAP )) {
+		wraplen = -1;
+	} else {
+		wraplen = LDIF_MAX_LINE_WIDTH;
+	}
+
+	/* put the type + ": " */
+	for ( p = (unsigned char *) t; *p; p++, len++ ) {
+		*(*out)++ = *p;
+	}
+	*(*out)++ = ':';
+	len++;
+	if ( LDIF_OPT_ISSET( options, LDIF_OPT_VALUE_IS_URL )) {
+		*(*out)++ = '<';	/* add '<' for URLs */
+		len++;
+	}
+	save = *out;
+	savelen = len;
+	b64 = 0;
+
+	stop = (unsigned char *)val;
+	if ( val && vlen > 0 ) {
+		*(*out)++ = ' ';
+		stop = (unsigned char *) (val + vlen);
+		if ( LDIF_OPT_ISSET( options, LDIF_OPT_MINIMAL_ENCODING )) {
+			if ( !LDIF_SAFE_INITCHAR( val[0] )) {
+				b64 = 1;
+			}
+		} else {
+			if ( !LDIF_CONSERVATIVE_INITCHAR( val[0] ) ||
+				 !LDIF_CONSERVATIVE_FINALCHAR( val[vlen-1] )) {
+				b64 = 1;
+			}
+		}
+	}
+
+	if ( !b64 ) {
+		for ( byte = (unsigned char *) val; byte < stop;
+		    byte++, len++ ) {
+			if ( LDIF_OPT_ISSET( options,
+			    LDIF_OPT_MINIMAL_ENCODING )) {
+				if ( !LDIF_SAFE_CHAR( *byte )) {
+					b64 = 1;
+					break;
+				}
+			} else if ( !LDIF_CONSERVATIVE_CHAR( *byte )) {
+				b64 = 1;
+				break;
+			}
+			
+			if ( wraplen != -1 && len > wraplen ) {
+				*(*out)++ = '\n';
+				*(*out)++ = ' ';
+				len = 1;
+			}
+			*(*out)++ = *byte;
+		}
+	}
+
+	if ( b64 ) {
+		*out = save;
+		*(*out)++ = ':';
+		*(*out)++ = ' ';
+		len = ldif_base64_encode_internal( (unsigned char *)val, *out, vlen,
+		    savelen + 2, wraplen );
+		*out += len;
+	}
+
+	*(*out)++ = '\n';
+}
+
+void 
+ldif_put_type_and_value( char **out, char *t, char *val, int vlen )
+{
+    ldif_put_type_and_value_with_options( out, t, val, vlen, 0 );
+}
+
+void 
+ldif_put_type_and_value_nowrap( char **out, char *t, char *val, int vlen )
+{
+    ldif_put_type_and_value_with_options( out, t, val, vlen, LDIF_OPT_NOWRAP );
+}
+
+/*
+ * ldif_base64_encode_internal - encode "srclen" bytes in "src", place BASE64
+ * encoded bytes in "dst" and return the length of the BASE64
+ * encoded string.  "dst" is also zero-terminated by this function.
+ *
+ * If "lenused" >= 0, newlines will be included in "dst" and "lenused" if
+ * appropriate.  "lenused" should be a count of characters already used
+ * on the current line.  The LDIF lines we create will contain at most
+ * "wraplen" characters on each line, unless "wraplen" is -1, in which
+ * case output line length is unlimited.
+ *
+ * If "lenused" < 0, no newlines will be included, and the LDIF_BASE64_LEN()
+ * macro can be used to determine how many bytes will be placed in "dst."
+ */
+
+static int
+ldif_base64_encode_internal( unsigned char *src, char *dst, int srclen, int lenused, int wraplen )
+{
+	unsigned char	*byte, *stop;
+	unsigned char	buf[3];
+	char		*out;
+	unsigned long	bits;
+	int		i, pad, len;
+
+	len = 0;
+	out = dst;
+	stop = src + srclen;
+
+	/* convert to base 64 (3 bytes => 4 base 64 digits) */
+	for ( byte = src; byte < stop - 2; byte += 3 ) {
+		bits = (byte[0] & 0xff) << 16;
+		bits |= (byte[1] & 0xff) << 8;
+		bits |= (byte[2] & 0xff);
+
+		for ( i = 0; i < 4; i++, bits <<= 6 ) {
+			if ( wraplen != -1 &&  lenused >= 0 && lenused++ > wraplen ) {
+				*out++ = '\n';
+				*out++ = ' ';
+				lenused = 2;
+			}
+
+			/* get b64 digit from high order 6 bits */
+			*out++ = nib2b64[ (bits & 0xfc0000L) >> 18 ];
+		}
+	}
+
+	/* add padding if necessary */
+	if ( byte < stop ) {
+		for ( i = 0; byte + i < stop; i++ ) {
+			buf[i] = byte[i];
+		}
+		for ( pad = 0; i < 3; i++, pad++ ) {
+			buf[i] = '\0';
+		}
+		byte = buf;
+		bits = (byte[0] & 0xff) << 16;
+		bits |= (byte[1] & 0xff) << 8;
+		bits |= (byte[2] & 0xff);
+
+		for ( i = 0; i < 4; i++, bits <<= 6 ) {
+			if ( wraplen != -1 && lenused >= 0 && lenused++ > wraplen ) {
+				*out++ = '\n';
+				*out++ = ' ';
+				lenused = 2;
+			}
+
+			if (( i == 3 && pad > 0 ) || ( i == 2 && pad == 2 )) {
+				/* Pad as appropriate */
+				*out++ = '=';
+			} else {
+				/* get b64 digit from low order 6 bits */
+				*out++ = nib2b64[ (bits & 0xfc0000L) >> 18 ];
+			}
+		}
+	}
+
+	*out = '\0';
+
+	return( out - dst );
+}
+
+int
+ldif_base64_encode( unsigned char *src, char *dst, int srclen, int lenused )
+{
+    return ldif_base64_encode_internal( src, dst, srclen, lenused, LDIF_MAX_LINE_WIDTH );
+}
+
+int
+ldif_base64_encode_nowrap( unsigned char *src, char *dst, int srclen, int lenused )
+{
+    return ldif_base64_encode_internal( src, dst, srclen, lenused, -1 );
+}
+
+
+/*
+ * return malloc'd, zero-terminated LDIF line
+ */
+char *
+ldif_type_and_value_with_options( char *type, char *val, int vlen,
+	unsigned long options )
+{
+    char	*buf, *p;
+    int		tlen;
+
+    tlen = strlen( type );
+    if (( buf = (char *)malloc( LDIF_SIZE_NEEDED( tlen, vlen ) + 1 )) !=
+	    NULL ) {
+	p = buf;
+	ldif_put_type_and_value_with_options( &p, type, val, vlen, options );
+	*p = '\0';
+    }
+
+    return( buf );
+}
+
+char *
+ldif_type_and_value( char *type, char *val, int vlen )
+{
+    return ldif_type_and_value_with_options( type, val, vlen, 0 );
+}
+
+char *
+ldif_type_and_value_nowrap( char *type, char *val, int vlen )
+{
+    return ldif_type_and_value_with_options( type, val, vlen, LDIF_OPT_NOWRAP );
+}
+
+/*
+ * ldif_get_entry - read the next ldif entry from the FILE referenced
+ * by fp. return a pointer to a malloc'd, null-terminated buffer. also
+ * returned is the last line number read, in *lineno.
+ */
+char *
+ldif_get_entry( FILE *fp, int *lineno )
+{
+	char	line[BUFSIZ];
+	char	*buf;
+	int	max, cur, len, gotsome;
+
+	buf = NULL;
+	max = cur = gotsome = 0;
+	while ( fgets( line, sizeof(line), fp ) != NULL ) {
+		if ( lineno != NULL ) {
+			(*lineno)++;
+		}
+		/* ldif entries are terminated by a \n on a line by itself */
+		if ( line[0] == '\0' || line[0] == '\n'
+#if !defined( XP_WIN32 )
+		     || ( line[0] == '\r' && line[1] == '\n' ) /* DOS format */
+#endif
+		   ) {
+			if ( gotsome ) {
+				break;
+			} else {
+				continue;
+			}
+		} else if ( line[0] == '#' ) {
+			continue;
+		}
+		gotsome = 1;
+		len = strlen( line );
+#if !defined( XP_WIN32 )
+		/* DOS format */
+		if ( len > 0 && line[len-1] == '\r' ) {
+			--len;
+			line[len] = '\0';
+		} else if ( len > 1 && line[len-2] == '\r' && line[len-1] == '\n' ) {
+			--len;
+			line[len-1] = line[len];
+			line[len] = '\0';
+		}
+#endif
+		while ( cur + (len + 1) > max ) {
+			if ( buf == NULL ) {
+				max += BUFSIZ;
+				buf = (char *) malloc( max );
+			} else {
+				max *= 2;
+				buf = (char *) realloc( buf, max );
+			}
+			if ( buf == NULL ) {
+				return( NULL );
+			}
+		}
+
+		memcpy( buf + cur, line, len + 1 );
+		cur += len;
+	}
+
+	return( buf );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libprldap/Makefile.in
@@ -0,0 +1,250 @@
+# 
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+# 
+# The contents of this file are subject to the Mozilla Public License Version 
+# 1.1 (the "License"); you may not use this file except in compliance with 
+# the License. You may obtain a copy of the License at 
+# http://www.mozilla.org/MPL/
+# 
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+# 
+# The Original Code is Mozilla Communicator client code, released
+# March 31, 1998.
+# 
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 1998-1999
+# the Initial Developer. All Rights Reserved.
+# 
+# Contributor(s):
+# 
+# Alternatively, the contents of this file may be used under the terms of
+# either of the GNU General Public License Version 2 or later (the "GPL"),
+# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+# 
+# ***** END LICENSE BLOCK ***** 
+
+MOD_DEPTH	= ../../..
+srcdir		= @srcdir@
+topsrcdir 	= @top_srcdir@
+NSPR_LIBS   = @NSPR_LIBS@
+NSPR_CFLAGS = @NSPR_CFLAGS@
+
+include $(MOD_DEPTH)/config/autoconf.mk
+include $(topsrcdir)/build.mk
+
+SRCS		= ldappr-dns.c \
+		  ldappr-error.c \
+		  ldappr-io.c \
+		  ldappr-public.c \
+		  ldappr-threads.c
+
+REALOBJS        = $(SRCS:.c=.$(OBJ_SUFFIX))
+OBJS		= $(addprefix $(OBJDIR_NAME)/, $(REALOBJS)) 
+
+DISTHDIR	= $(DIST)/public/ldap
+HDIR		= $(topsrcdir)/ldap/include
+
+ifneq (,$(filter OS2 WINNT,$(OS_ARCH)))
+LIBPRLDAP	= $(addprefix $(OBJDIR_NAME)/, \
+			$(LIB_PREFIX)$(PRLDAP_LIBNAME).$(LIB_SUFFIX))
+else
+LIBPRLDAP =
+endif
+DLLPRLDAP	= $(addprefix $(OBJDIR_NAME)/, \
+			$(LIB_PREFIX)$(PRLDAP_LIBNAME).$(DLL_SUFFIX))
+
+INSTALLDIR      = $(DIST)/$(OBJDIR_NAME)
+
+RELEASE_LIBS	= $(DLLPRLDAP)
+
+include $(topsrcdir)/config/rules.mk
+
+GARBAGE 	+= $(LIBPRLDAP) $(DLLPRLDAP)
+
+LOCAL_INCLUDES  =
+INCLUDES	+= -I$(DISTHDIR) -I$(HDIR) -I$(INSTALLDIR)/include \
+                   $(NSPR_CFLAGS)
+DEFINES		+= $(DEFS)
+
+PLATFORMCFLAGS	= -DUSE_WAITPID -DNEEDPROTOS
+PLATFORMLIBS	=
+THREADS		=
+THREADSLIB	=
+
+#
+# shared library symbol export definitions
+#
+ifeq ($(USE_DLL_EXPORTS_FILE), 1)
+ifeq ($(OS_ARCH), WINNT)
+GENEXPORTS=cmd /c  $(PERL) $(topsrcdir)/ldap/build/genexports.pl
+else
+GENEXPORTS=$(PERL) $(topsrcdir)/ldap/build/genexports.pl
+endif
+
+# variable definitions for exported symbols
+ifeq ($(OS_ARCH), WINNT)
+        PRLDAP_EXPORT_DEFS= $(WIN_TOP_SRC)/ldap/libraries/msdos/winsock/nsldappr32.def
+else
+ifeq ($(OS_ARCH), OS2)
+        PRLDAP_EXPORT_DEFS= $(OBJDIR_NAME)/libprldap.def
+else
+        PRLDAP_EXPORT_DEFS= $(OBJDIR_NAME)/libprldap.exp
+endif
+GARBAGE += $(LDAP_EXPORT_DEFS)
+endif
+
+PRLDAP_EXPORT_FLAGS=$(addprefix $(DLLEXPORTS_PREFIX), $(PRLDAP_EXPORT_DEFS))
+
+GENEXPARGS=$(BUILD_DEBUG) $(PRLDAPVERS_SUFFIX) $(PRLDAPVERS)
+endif # USE_DLL_EXPORTS_FILE
+
+ifeq ($(OS_ARCH), WINNT)
+ifdef NS_USE_GCC
+EXTRA_DLL_LIBS =-L$(dist_libdir) -l$(LDAP_LIBNAME) \
+	$(NSPRLINK)
+else
+EXTRA_LIBS =wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib \
+            comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib \
+            rpcrt4.lib uuid.lib winmm.lib
+EXTRA_LIBS += $(dist_libdir)/$(LDAP_LIBNAME).lib
+EXTRA_LIBS += $(NSPRLINK)
+endif
+CUSTOM_LIBS=1
+endif
+
+ifeq ($(OS_ARCH),OS2)
+EXTRA_LIBS = $(dist_libdir)/$(LDAP_LIBNAME).lib
+EXTRA_LIBS += $(dist_libdir)/$(LBER_LIBNAME).lib
+EXTRA_LIBS += $(NSPRLINK)
+EXTRA_LIBS += $(OS_LIBS)
+CUSTOM_LIBS=1
+endif
+
+ifeq ($(OS_ARCH), OSF1)
+EXTRA_LIBS = -L$(dist_libdir) -l$(LDAP_LIBNAME)
+EXTRA_LIBS += $(NSPRLINK)
+EXTRA_LIBS += -lcxx -lpthread -lrt -lmach -lexc
+CUSTOM_LIBS=1
+endif
+
+ifeq ($(OS_ARCH), AIX)
+EXTRA_LIBS = -L$(dist_libdir) -l$(LDAP_LIBNAME)
+EXTRA_LIBS += $(NSPRLINK)
+EXTRA_LIBS += -ldl -brtl -lpthreads -lc_r -lm
+CUSTOM_LIBS=1
+endif
+
+# no extra libs on HP-UX
+ifeq ($(OS_ARCH), HP-UX)
+CUSTOM_LIBS=1
+endif
+
+# if you need to do something extra for extra_libs or extra_dll_libs for a
+# specific platform, do them above according the other ones for WINNT, OS2, etc.
+# then define CUSTOM_LIBS=1 - if you just want the standard ones as defined
+# below, you don't have to do anything
+ifndef CUSTOM_LIBS
+EXTRA_LIBS = -L$(dist_libdir) -l$(LDAP_LIBNAME)
+EXTRA_LIBS += $(NSPRLINK)
+endif
+
+OBJDEST = $(OBJDIR_NAME)
+
+###########################################################################
+
+ifeq ($(USE_DLL_EXPORTS_FILE), 1)
+# recursive gmake rule to create exported symbols file
+$(PRLDAP_EXPORT_DEFS):: $(srcdir)/libprldap.ex
+ifeq ($(OS_ARCH), WINNT)
+	$(GENEXPORTS) Win32 $(srcdir)/../msdos/winsock/nsldappr32.tdf $< $(GENEXPARGS) > $@
+else
+ifeq ($(OS_ARCH), OS2)
+	echo LIBRARY $(PRLDAP_LIBNAME) INITINSTANCE TERMINSTANCE > $@
+	echo PROTMODE >> $@
+	echo CODE    LOADONCALL MOVEABLE DISCARDABLE >> $@
+	echo DATA    PRELOAD MOVEABLE MULTIPLE NONSHARED >> $@
+	echo EXPORTS >> $@
+	$(GENEXPORTS) $(OS_ARCH) Standard $< $(GENEXPARGS) >> $@
+else
+	$(GENEXPORTS) $(OS_ARCH) Standard $< $(GENEXPARGS) > $@
+endif
+endif
+endif # USE_DLL_EXPORTS_FILE
+
+versiont.c:	Makefile.client Version.c
+	@$(RM) $@
+	@(u="$${USER-root}" v="$(shell cat ../../build/version)" d="$(shell pwd)" \
+	h="$(shell hostname)" t="$(shell date)"; $(SED) -e "s|%WHEN%|$${t}|" \
+	-e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
+	-e "s|%VERSION%|$${v}|" \
+	< Version.c > $@)
+
+export::    $(OBJDEST) $(LIBDIR) $(OBJS) $(DLLPRLDAP)
+
+$(LIBDIR):
+	$(MKDIR) $(LIBDIR)
+
+$(LIBPRLDAP): $(OBJS) $(LIBDIR) $(PRLDAP_EXPORT_DEFS)
+	@echo ======= making $(LIBPRLDAP)
+ifdef SO_FILES_TO_REMOVE
+	-$(RM) $(SO_FILES_TO_REMOVE)
+endif
+ifeq ($(OS_ARCH),OS2)
+# create import library for OS/2
+	rm -f $@
+	$(IMPLIB) $@ $(PRLDAP_EXPORT_DEFS)
+else
+	$(LINK_LIB) $(EXTRA_LIBS)
+endif
+
+$(DLLPRLDAP): $(OBJS) $(LIBDIR) $(PRLDAP_EXPORT_DEFS)
+	@echo ======= making $(DLLPRLDAP)
+ifdef SO_FILES_TO_REMOVE
+	-$(RM) $(SO_FILES_TO_REMOVE)
+endif
+	$(LINK_DLL) $(PRLDAP_EXPORT_FLAGS) $(EXTRA_LIBS)
+
+veryclean:: clean
+
+$(OBJDEST):
+	$(MKDIR) $(OBJDEST)
+
+# the $(dist_bindir) line is for the mozilla client, which for reasons
+# unknown wants shared libraries in /bin also
+#
+# Set the default sources for the export target
+EXPDEPS2 = $(LIBPRLDAP) $(DLLPRLDAP)	
+# Remove the LIB source if on win32 and using MSVC
+# This avoids problems with -jX builds where 'link' will make both the
+# .dll and .lib files in one pass
+ifeq ($(OS_ARCH), WINNT)
+ifeq ($(LD),link)
+EXPDEPS2 = $(DLLPRLDAP)	
+endif
+endif
+
+export::	$(EXPDEPS2)
+ifeq ($(OS_ARCH), WINNT)
+	$(INSTALL) -m 555 $(LIBPRLDAP) $(dist_libdir)
+	$(INSTALL) -m 555 $(DLLPRLDAP) $(dist_libdir)
+endif
+ifeq ($(OS_ARCH),OS2)
+	$(INSTALL) -m 444 $(LIBPRLDAP) $(dist_libdir)
+endif
+ifdef MKSHLIB
+	$(INSTALL) -m 555 $(DLLPRLDAP) $(dist_libdir)
+	$(INSTALL) -m 444 $(DLLPRLDAP) $(dist_bindir)
+endif
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libprldap/ldappr-dns.c
@@ -0,0 +1,166 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * DNS callback functions for libldap that use the NSPR (Netscape
+ * Portable Runtime) thread API.
+ *
+ */
+
+#include "ldappr-int.h"
+
+static LDAPHostEnt *prldap_gethostbyname( const char *name,
+	LDAPHostEnt *result, char *buffer, int buflen, int *statusp,
+	void *extradata );
+static LDAPHostEnt *prldap_gethostbyaddr( const char *addr, int length,
+	int type, LDAPHostEnt *result, char *buffer, int buflen,
+	int *statusp, void *extradata );
+static int prldap_getpeername( LDAP *ld, struct sockaddr *addr,
+	char *buffer, int buflen );
+static LDAPHostEnt *prldap_convert_hostent( LDAPHostEnt *ldhp,
+	PRHostEnt *prhp );
+
+
+/*
+ * Install NSPR DNS functions into ld (if ld is NULL, they are installed
+ * as the default functions for new LDAP * handles).
+ *
+ * Returns 0 if all goes well and -1 if not.
+ */
+int
+prldap_install_dns_functions( LDAP *ld )
+{
+    struct ldap_dns_fns			dnsfns;
+
+    memset( &dnsfns, '\0', sizeof(struct ldap_dns_fns) );
+    dnsfns.lddnsfn_bufsize = PR_NETDB_BUF_SIZE;
+    dnsfns.lddnsfn_gethostbyname = prldap_gethostbyname;
+    dnsfns.lddnsfn_gethostbyaddr = prldap_gethostbyaddr;
+    dnsfns.lddnsfn_getpeername = prldap_getpeername;
+    if ( ldap_set_option( ld, LDAP_OPT_DNS_FN_PTRS, (void *)&dnsfns ) != 0 ) {
+	return( -1 );
+    }
+
+    return( 0 );
+}
+
+
+static LDAPHostEnt *
+prldap_gethostbyname( const char *name, LDAPHostEnt *result,
+	char *buffer, int buflen, int *statusp, void *extradata )
+{
+    PRHostEnt	prhent;
+
+    if( !statusp || ( *statusp = (int)PR_GetIPNodeByName( name,
+		PRLDAP_DEFAULT_ADDRESS_FAMILY, PR_AI_DEFAULT,
+		buffer, buflen, &prhent )) == PR_FAILURE ) {
+	return( NULL );
+    }
+
+    return( prldap_convert_hostent( result, &prhent ));
+}
+
+
+static LDAPHostEnt *
+prldap_gethostbyaddr( const char *addr, int length, int type,
+	LDAPHostEnt *result, char *buffer, int buflen, int *statusp,
+	void *extradata )
+{
+    PRHostEnt	prhent;
+    PRNetAddr	iaddr;
+
+    if ( NULL == statusp ) {
+	return( NULL );
+    }
+
+    memset( &iaddr, 0, sizeof( iaddr ));
+    if ( PR_StringToNetAddr( addr, &iaddr ) == PR_FAILURE ) {
+	return( NULL );
+    }
+    PRLDAP_SET_PORT( &iaddr, 0 );
+
+    if( PR_FAILURE == (*statusp =
+			PR_GetHostByAddr(&iaddr, buffer, buflen, &prhent ))) {
+	return( NULL );
+    }
+
+    return( prldap_convert_hostent( result, &prhent ));
+}
+
+
+static int
+prldap_getpeername( LDAP *ld, struct sockaddr *addr, char *buffer, int buflen)
+{
+    PRLDAPIOSocketArg *sa;
+    PRNetAddr	iaddr;
+    int		ret;
+
+    if (NULL != ld) {
+	    ret = prldap_socket_arg_from_ld( ld, &sa );
+	    if (ret != LDAP_SUCCESS) {
+		return (-1);
+	    }
+	    ret = PR_GetPeerName(sa->prsock_prfd, &iaddr);
+	    if( ret == PR_FAILURE ) {
+		return( -1 );
+	    }
+	    *addr = *((struct sockaddr *)&iaddr.raw);
+	    ret = PR_NetAddrToString(&iaddr, buffer, buflen);
+	    if( ret == PR_FAILURE ) {
+		return( -1 );
+	    }
+	    return (0);
+    }
+    return (-1);
+}
+
+
+/*
+ * Function: prldap_convert_hostent()
+ * Description: copy the fields of a PRHostEnt struct to an LDAPHostEnt
+ * Returns: the LDAPHostEnt pointer passed in.
+ */
+static LDAPHostEnt *
+prldap_convert_hostent( LDAPHostEnt *ldhp, PRHostEnt *prhp )
+{
+	ldhp->ldaphe_name = prhp->h_name;
+	ldhp->ldaphe_aliases = prhp->h_aliases;
+	ldhp->ldaphe_addrtype = prhp->h_addrtype;
+	ldhp->ldaphe_length =  prhp->h_length;
+	ldhp->ldaphe_addr_list =  prhp->h_addr_list;
+	return( ldhp );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libprldap/ldappr-error.c
@@ -0,0 +1,335 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Utilities for manageing the relationship between NSPR errors and
+ * OS (errno-style) errors.
+ *
+ * The overall strategy used is to map NSPR errors into OS errors.
+ */
+
+#include "ldappr-int.h"
+
+void
+prldap_set_system_errno( int oserrno )
+{
+    PR_SetError( PR_GetError(), oserrno );
+}
+
+
+int
+prldap_get_system_errno( void )
+{
+    return( PR_GetOSError());
+}
+
+/*
+ * Retrieve the NSPR error number, convert to a system error code, and return
+ * the result.
+ */
+struct prldap_errormap_entry {
+    PRInt32	erm_nspr;	/* NSPR error code */
+    int		erm_system;	/* corresponding system error code */
+};
+
+/* XXX: not sure if this extra mapping for Windows is good or correct */
+#ifdef _WINDOWS
+#ifndef ENOTSUP
+#define ENOTSUP		-1
+#endif
+#ifndef ETIMEDOUT
+#define ETIMEDOUT	WSAETIMEDOUT
+#endif
+#ifndef EADDRNOTAVAIL
+#define EADDRNOTAVAIL	WSAEADDRNOTAVAIL
+#endif
+#ifndef EAFNOSUPPORT
+#define EAFNOSUPPORT	WSAEAFNOSUPPORT
+#endif
+#ifndef EISCONN
+#define EISCONN		WSAEISCONN
+#endif
+#ifndef EADDRINUSE
+#define EADDRINUSE	WSAEADDRINUSE
+#endif
+#ifndef ECONNREFUSED
+#define ECONNREFUSED	WSAECONNREFUSED
+#endif
+#ifndef EHOSTUNREACH
+#define EHOSTUNREACH	WSAEHOSTUNREACH
+#endif
+#ifndef ENOTCONN
+#define ENOTCONN	WSAENOTCONN
+#endif
+#ifndef ENOTSOCK
+#define ENOTSOCK	WSAENOTSOCK
+#endif
+#ifndef EPROTOTYPE
+#define EPROTOTYPE	WSAEPROTOTYPE
+#endif
+#ifndef EOPNOTSUPP
+#define EOPNOTSUPP	WSAEOPNOTSUPP
+#endif
+#ifndef EPROTONOSUPPORT
+#define EPROTONOSUPPORT	WSAEPROTONOSUPPORT
+#endif
+#ifndef EOVERFLOW
+#define EOVERFLOW	-1
+#endif
+#ifndef ECONNRESET
+#define ECONNRESET	WSAECONNRESET
+#endif
+#ifndef ELOOP
+#define ELOOP		WSAELOOP
+#endif
+#ifndef ENOTBLK
+#define ENOTBLK		-1
+#endif
+#ifndef ETXTBSY
+#define ETXTBSY		-1
+#endif
+#ifndef ENETDOWN
+#define ENETDOWN	WSAENETDOWN
+#endif
+#ifndef ESHUTDOWN
+#define ESHUTDOWN	WSAESHUTDOWN
+#endif
+#ifndef ECONNABORTED
+#define ECONNABORTED	WSAECONNABORTED
+#endif
+#endif /* _WINDOWS */
+
+#if defined(macintosh)
+/*
+ * Some Unix error defs. Under CW 7, we can't define OTUNIXERRORS because
+ * it generates many conflicts with errno.h. Define what we need here.
+ * These need to be in sync with OpenTransport.h
+ */
+#define EWOULDBLOCK     35
+#define ENOTSOCK        38
+#define EPROTOTYPE      41
+#define EPROTONOSUPPORT 43
+#define EOPNOTSUPP      45
+#define EADDRINUSE      48
+#define EADDRNOTAVAIL   49
+#define ENETDOWN        50
+#define ECONNABORTED    53
+#define ECONNRESET      54
+#define EISCONN         56
+#define ENOTCONN        57
+#define ESHUTDOWN       58
+#define ETIMEDOUT       60
+#define ECONNREFUSED    61
+#define EHOSTUNREACH    65
+#define EAFNOSUPPORT    -1
+#define ELOOP           -1
+#define ENOTBLK         -1
+#define ENOTSUP         -1
+#define EOVERFLOW       -1
+#define ETXTBSY         -1
+#endif /* macintosh */
+
+#ifdef XP_OS2
+#define SOCBASEERR      0
+#endif
+#ifndef ENOTSUP
+#define ENOTSUP         -1
+#endif
+#ifndef EOVERFLOW
+#define EOVERFLOW       -1
+#endif
+#ifndef EDEADLOCK
+#define EDEADLOCK       -1
+#endif
+#ifndef EFAULT
+#define EFAULT          SOCEFAULT
+#endif
+#ifndef EPIPE
+#define EPIPE           SOCEPIPE
+#endif
+#ifndef EIO
+#define EIO             (SOCBASEERR+5)
+#endif
+#ifndef EDEADLK
+#define EDEADLK         (SOCBASEERR+11)
+#endif
+#ifndef ENOTBLK
+#define ENOTBLK         (SOCBASEERR+15)
+#endif
+#ifndef EBUSY
+#define EBUSY           (SOCBASEERR+16)
+#endif
+#ifndef ENOTDIR
+#define ENOTDIR         (SOCBASEERR+20)
+#endif
+#ifndef EISDIR
+#define EISDIR          (SOCBASEERR+21)
+#endif
+#ifndef ENFILE
+#define ENFILE          (SOCBASEERR+23)
+#endif
+#ifndef ETXTBSY
+#define ETXTBSY         (SOCBASEERR+26)
+#endif
+#ifndef EFBIG
+#define EFBIG           (SOCBASEERR+27)
+#endif
+#ifndef ESPIPE
+#define ESPIPE          (SOCBASEERR+29)
+#endif
+#ifndef EROFS
+#define EROFS           (SOCBASEERR+30)
+#endif
+
+#ifdef BEOS
+#define ENOTSUP         -1
+#define ENOTBLK         -1
+#define ETXTBSY         -1
+#endif
+
+#if defined(BSDI) || defined(OPENBSD) || defined (NETBSD)
+#define ENOTSUP		-1
+#endif
+
+#if defined(OSF1) || defined(BSDI) || defined(VMS) || defined(OPENBSD)
+#define EOVERFLOW       -1
+#endif
+
+#if defined(__hpux) || defined(_AIX) || defined(OSF1) || defined(DARWIN) || \
+  defined(BEOS) || defined(FREEBSD) || defined(BSDI) || defined(VMS) || \
+  defined(OPENBSD) || defined(NETBSD)
+#define EDEADLOCK       -1
+#endif
+
+/* XXX: need to verify that the -1 entries are correct (no mapping) */
+static struct prldap_errormap_entry prldap_errormap[] = {
+    {  PR_OUT_OF_MEMORY_ERROR, ENOMEM },
+    {  PR_BAD_DESCRIPTOR_ERROR, EBADF },
+    {  PR_WOULD_BLOCK_ERROR, EAGAIN },
+    {  PR_ACCESS_FAULT_ERROR, EFAULT },
+    {  PR_INVALID_METHOD_ERROR, EINVAL },	/* XXX: correct mapping ? */
+    {  PR_ILLEGAL_ACCESS_ERROR, EACCES },	/* XXX: correct mapping ? */
+    {  PR_UNKNOWN_ERROR, -1 },
+    {  PR_PENDING_INTERRUPT_ERROR, -1 },
+    {  PR_NOT_IMPLEMENTED_ERROR, ENOTSUP },
+    {  PR_IO_ERROR, EIO },
+    {  PR_IO_TIMEOUT_ERROR, ETIMEDOUT },	/* XXX: correct mapping ? */
+    {  PR_IO_PENDING_ERROR, -1 },
+    {  PR_DIRECTORY_OPEN_ERROR, ENOTDIR },
+    {  PR_INVALID_ARGUMENT_ERROR, EINVAL },
+    {  PR_ADDRESS_NOT_AVAILABLE_ERROR, EADDRNOTAVAIL },
+    {  PR_ADDRESS_NOT_SUPPORTED_ERROR, EAFNOSUPPORT },
+    {  PR_IS_CONNECTED_ERROR, EISCONN },
+    {  PR_BAD_ADDRESS_ERROR, EFAULT },		/* XXX: correct mapping ? */
+    {  PR_ADDRESS_IN_USE_ERROR, EADDRINUSE },
+    {  PR_CONNECT_REFUSED_ERROR, ECONNREFUSED },
+    {  PR_NETWORK_UNREACHABLE_ERROR, EHOSTUNREACH },
+    {  PR_CONNECT_TIMEOUT_ERROR, ETIMEDOUT },
+    {  PR_NOT_CONNECTED_ERROR, ENOTCONN },
+    {  PR_LOAD_LIBRARY_ERROR, -1 },
+    {  PR_UNLOAD_LIBRARY_ERROR, -1 },
+    {  PR_FIND_SYMBOL_ERROR, -1 },
+    {  PR_INSUFFICIENT_RESOURCES_ERROR, -1 },
+    {  PR_DIRECTORY_LOOKUP_ERROR, EHOSTUNREACH },/* an approximation */
+    {  PR_TPD_RANGE_ERROR, -1 },
+    {  PR_PROC_DESC_TABLE_FULL_ERROR, -1 },
+    {  PR_SYS_DESC_TABLE_FULL_ERROR, -1 },
+    {  PR_NOT_SOCKET_ERROR, ENOTSOCK },
+    {  PR_NOT_TCP_SOCKET_ERROR, EPROTOTYPE },
+    {  PR_SOCKET_ADDRESS_IS_BOUND_ERROR, -1 },
+    {  PR_NO_ACCESS_RIGHTS_ERROR, EACCES },	/* XXX: correct mapping ? */
+    {  PR_OPERATION_NOT_SUPPORTED_ERROR, EOPNOTSUPP },
+    {  PR_PROTOCOL_NOT_SUPPORTED_ERROR, EPROTONOSUPPORT },
+    {  PR_REMOTE_FILE_ERROR, -1 },
+    {  PR_BUFFER_OVERFLOW_ERROR, EOVERFLOW },
+    {  PR_CONNECT_RESET_ERROR, ECONNRESET },
+    {  PR_RANGE_ERROR, ERANGE },
+    {  PR_DEADLOCK_ERROR, EDEADLK },
+    {  PR_FILE_IS_LOCKED_ERROR, EDEADLOCK },	/* XXX: correct mapping ? */
+    {  PR_FILE_TOO_BIG_ERROR, EFBIG },
+    {  PR_NO_DEVICE_SPACE_ERROR, ENOSPC },
+    {  PR_PIPE_ERROR, EPIPE },
+    {  PR_NO_SEEK_DEVICE_ERROR, ESPIPE },
+    {  PR_IS_DIRECTORY_ERROR, EISDIR },
+    {  PR_LOOP_ERROR, ELOOP },
+    {  PR_NAME_TOO_LONG_ERROR, ENAMETOOLONG },
+    {  PR_FILE_NOT_FOUND_ERROR, ENOENT },
+    {  PR_NOT_DIRECTORY_ERROR, ENOTDIR },
+    {  PR_READ_ONLY_FILESYSTEM_ERROR, EROFS },
+    {  PR_DIRECTORY_NOT_EMPTY_ERROR, ENOTEMPTY },
+    {  PR_FILESYSTEM_MOUNTED_ERROR, EBUSY },
+    {  PR_NOT_SAME_DEVICE_ERROR, EXDEV },
+    {  PR_DIRECTORY_CORRUPTED_ERROR, -1 },
+    {  PR_FILE_EXISTS_ERROR, EEXIST },
+    {  PR_MAX_DIRECTORY_ENTRIES_ERROR, -1 },
+    {  PR_INVALID_DEVICE_STATE_ERROR, ENOTBLK }, /* XXX: correct mapping ? */
+    {  PR_DEVICE_IS_LOCKED_ERROR, -2 },
+    {  PR_NO_MORE_FILES_ERROR, ENFILE },
+    {  PR_END_OF_FILE_ERROR, -1 },
+    {  PR_FILE_SEEK_ERROR, ESPIPE },		/* XXX: correct mapping ? */
+    {  PR_FILE_IS_BUSY_ERROR, ETXTBSY },
+    {  PR_OPERATION_ABORTED_ERROR, -1 },
+    {  PR_IN_PROGRESS_ERROR, -1 },
+    {  PR_ALREADY_INITIATED_ERROR, -1 },
+    {  PR_GROUP_EMPTY_ERROR, -1 },
+    {  PR_INVALID_STATE_ERROR, -1 },
+    {  PR_NETWORK_DOWN_ERROR, ENETDOWN },
+    {  PR_SOCKET_SHUTDOWN_ERROR, ESHUTDOWN },
+    {  PR_CONNECT_ABORTED_ERROR, ECONNABORTED },
+    {  PR_HOST_UNREACHABLE_ERROR, EHOSTUNREACH },
+    {  PR_MAX_ERROR, -1 },
+};
+
+
+int
+prldap_prerr2errno( void )
+{
+    int		oserr, i;
+    PRInt32	nsprerr;
+
+    nsprerr = PR_GetError();
+
+    oserr = -1;		/* unknown */
+    for ( i = 0; prldap_errormap[i].erm_nspr != PR_MAX_ERROR; ++i ) {
+	if ( prldap_errormap[i].erm_nspr == nsprerr ) {
+	    oserr = prldap_errormap[i].erm_system;
+	    break;
+	}
+    }
+
+    return( oserr );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libprldap/ldappr-int.h
@@ -0,0 +1,139 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Internal header for libprldap -- glue NSPR (Netscape Portable Runtime)
+ * to libldap.
+ *
+ */
+
+#include "ldap.h"
+#include "nspr.h"
+#include "ldappr.h"
+
+#include <errno.h>
+#include <string.h>
+#include <stdarg.h>
+
+/*
+ * Macros:
+ */
+
+/* #define PRLDAP_DEBUG	1	*/ 	/* uncomment to enable debugging printfs */
+
+/*
+ * All of the sockets we use are IPv6 capable.
+ * Change the following #define to PR_AF_INET to support IPv4 only.
+ */
+#define PRLDAP_DEFAULT_ADDRESS_FAMILY	PR_AF_INET6
+
+/*
+ * Max length for sending message with one PR_Send.
+ * If a single message is larger than this size, the message is divided
+ * into multiple pieces up to this length and sent out.  This is necessary
+ * on Microsoft Windows at least where attempts to send really large
+ * messages in one PR_Send() call result in an error.
+ */
+#define PRLDAP_MAX_SEND_SIZE (8*1024*1024) /* 8MB */
+
+/*
+ * Macro to set port to the 'port' field of a NSPR PRNetAddr union.
+ ** INPUTS:
+ ** PRNetAddr *myaddr   A network address.
+ ** PRUint16   myport   port to set to the 'port' field of 'addr'.
+ ** RETURN: none
+ */
+#define PRLDAP_SET_PORT(myaddr,myport) \
+    ((myaddr)->raw.family == PR_AF_INET6 ? ((myaddr)->ipv6.port = PR_htons(myport)) : ((myaddr)->inet.port = PR_htons(myport)))
+
+/*
+ * Data structures:
+ */
+
+/* data structure that populates the I/O callback session arg. */
+typedef struct lextiof_session_private {
+	PRPollDesc	*prsess_pollds;		/* for poll callback */
+	int		prsess_pollds_count;	/* # of elements in pollds */
+	int		prsess_io_max_timeout;	/* in milliseconds */
+	void		*prsess_appdata;	/* application specific data */
+} PRLDAPIOSessionArg;
+
+/* data structure that populates the I/O callback socket-specific arg. */
+typedef struct lextiof_socket_private {
+	PRFileDesc	*prsock_prfd;		/* associated NSPR file desc. */
+	int		prsock_io_max_timeout;	/* in milliseconds */
+	void		*prsock_appdata;	/* application specific data */
+} PRLDAPIOSocketArg;
+
+
+/*
+ * Function prototypes:
+ */
+
+/*
+ * From ldapprio.c:
+ */
+int prldap_install_io_functions( LDAP *ld, int shared );
+int prldap_session_arg_from_ld( LDAP *ld, PRLDAPIOSessionArg **sessargpp );
+int prldap_set_io_max_timeout( PRLDAPIOSessionArg *prsessp,
+	int io_max_timeout );
+int prldap_get_io_max_timeout( PRLDAPIOSessionArg *prsessp,
+	int *io_max_timeoutp );
+int prldap_socket_arg_from_ld( LDAP *ld, PRLDAPIOSocketArg **sockargpp );
+PRLDAPIOSocketArg *prldap_socket_arg_alloc( PRLDAPIOSessionArg *sessionarg );
+
+
+/*
+ * From ldapprthreads.c:
+ */
+int prldap_install_thread_functions( LDAP *ld, int shared );
+int prldap_thread_new_handle( LDAP *ld, void *sessionarg );
+void prldap_thread_dispose_handle( LDAP *ld, void *sessionarg );
+
+
+/*
+ * From ldapprdns.c:
+ */
+int prldap_install_dns_functions( LDAP *ld );
+
+
+/*
+ * From ldapprerror.c:
+ */
+void prldap_set_system_errno( int e );
+int prldap_get_system_errno( void );
+int prldap_prerr2errno( void );
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libprldap/ldappr-io.c
@@ -0,0 +1,744 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Extended I/O callback functions for libldap that use
+ * NSPR (Netscape Portable Runtime) I/O.
+ *
+ * High level strategy: we use the socket-specific arg to hold our own data
+ * structure that includes the NSPR file handle (PRFileDesc *), among other
+ * useful information.  We use the default argument to hold an LDAP session
+ * handle specific data structure.
+ */
+
+#include "ldappr-int.h"
+
+#define PRLDAP_POLL_ARRAY_GROWTH  5  /* grow arrays 5 elements at a time */
+
+/*
+ * Local function prototypes:
+ */
+static PRIntervalTime prldap_timeout2it( int ms_timeout, int ms_maxtimeout );
+static int LDAP_CALLBACK prldap_read( int s, void *buf, int bufsize,
+	struct lextiof_socket_private *socketarg );
+static int LDAP_CALLBACK prldap_write( int s, const void *buf, int len,
+	struct lextiof_socket_private *socketarg );
+static int LDAP_CALLBACK prldap_poll( LDAP_X_PollFD fds[], int nfds,
+	int timeout, struct lextiof_session_private *sessionarg );
+static int LDAP_CALLBACK prldap_connect( const char *hostlist, int defport,
+	int timeout, unsigned long options,
+	struct lextiof_session_private *sessionarg,
+	struct lextiof_socket_private **socketargp );
+static int LDAP_CALLBACK prldap_close( int s,
+	struct lextiof_socket_private *socketarg );
+static int LDAP_CALLBACK prldap_newhandle( LDAP *ld,
+	struct lextiof_session_private *sessionarg );
+static void LDAP_CALLBACK prldap_disposehandle( LDAP *ld,
+	struct lextiof_session_private *sessionarg );
+static int LDAP_CALLBACK prldap_shared_newhandle( LDAP *ld,
+	struct lextiof_session_private *sessionarg );
+static void LDAP_CALLBACK prldap_shared_disposehandle( LDAP *ld,
+	struct lextiof_session_private *sessionarg );
+static PRLDAPIOSessionArg *prldap_session_arg_alloc( void );
+static void prldap_session_arg_free( PRLDAPIOSessionArg **prsesspp );
+static void prldap_socket_arg_free( PRLDAPIOSocketArg **prsockpp );
+static void *prldap_safe_realloc( void *ptr, PRUint32 size );
+
+
+
+/*
+ * Local macros:
+ */
+/* given a socket-specific arg, return the corresponding PRFileDesc * */
+#define PRLDAP_GET_PRFD( socketarg )	\
+		(((PRLDAPIOSocketArg *)(socketarg))->prsock_prfd)
+
+/*
+ * Static variables.
+ */
+static int prldap_default_io_max_timeout = LDAP_X_IO_TIMEOUT_NO_TIMEOUT;
+
+
+/*
+ * Install NSPR I/O functions into ld (if ld is NULL, they are installed
+ * as the default functions for new LDAP * handles).
+ *
+ * Returns 0 if all goes well and -1 if not.
+ */
+int
+prldap_install_io_functions( LDAP *ld, int shared )
+{
+    struct ldap_x_ext_io_fns	iofns;
+
+    memset( &iofns, 0, sizeof(iofns));
+    iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE;
+    iofns.lextiof_read = prldap_read;
+    iofns.lextiof_write = prldap_write;
+    iofns.lextiof_poll = prldap_poll;
+    iofns.lextiof_connect = prldap_connect;
+    iofns.lextiof_close = prldap_close;
+    if ( shared ) {
+	iofns.lextiof_newhandle = prldap_shared_newhandle;
+	iofns.lextiof_disposehandle = prldap_shared_disposehandle;
+    } else {
+	iofns.lextiof_newhandle = prldap_newhandle;
+	iofns.lextiof_disposehandle = prldap_disposehandle;
+    }
+    if ( NULL != ld ) {
+	/*
+	 * If we are dealing with a real ld, we allocate the session specific
+	 * data structure now.  If not allocated here, it will be allocated
+	 * inside prldap_newhandle() or prldap_shared_newhandle().
+	 */
+	if ( NULL ==
+		( iofns.lextiof_session_arg = prldap_session_arg_alloc())) {
+	    ldap_set_lderrno( ld, LDAP_NO_MEMORY, NULL, NULL );
+	    return( -1 );
+	}
+    } else {
+	iofns.lextiof_session_arg = NULL;
+    }
+
+    if ( ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, &iofns ) != 0 ) {
+	prldap_session_arg_free(
+		(PRLDAPIOSessionArg **) &iofns.lextiof_session_arg );
+	return( -1 );
+    }
+
+    return( 0 );
+}
+
+
+static PRIntervalTime
+prldap_timeout2it( int ms_timeout, int ms_maxtimeout )
+{
+    PRIntervalTime	prit;
+
+    if ( LDAP_X_IO_TIMEOUT_NO_WAIT == ms_timeout ) {
+	prit = PR_INTERVAL_NO_WAIT;
+    } else if ( LDAP_X_IO_TIMEOUT_NO_TIMEOUT == ms_timeout ) {
+	prit = PR_INTERVAL_NO_TIMEOUT;
+    } else {
+	prit = PR_MillisecondsToInterval( ms_timeout );
+    }
+
+    /* cap at maximum I/O timeout */
+    if ( LDAP_X_IO_TIMEOUT_NO_WAIT == ms_maxtimeout ) {
+	prit = LDAP_X_IO_TIMEOUT_NO_WAIT;
+    } else if ( LDAP_X_IO_TIMEOUT_NO_TIMEOUT != ms_maxtimeout ) {
+	if ( LDAP_X_IO_TIMEOUT_NO_TIMEOUT == ms_timeout ||
+		    ms_timeout > ms_maxtimeout ) {
+	    prit = PR_MillisecondsToInterval( ms_maxtimeout );
+	}
+    }
+
+#ifdef PRLDAP_DEBUG
+    if ( PR_INTERVAL_NO_WAIT == prit ) {
+	fprintf( stderr, "prldap_timeout2it: NO_WAIT\n" );
+    } else if ( PR_INTERVAL_NO_TIMEOUT == prit ) {
+	fprintf( stderr, "prldap_timeout2it: NO_TIMEOUT\n" );
+    } else {
+	fprintf( stderr, "prldap_timeout2it: %dms\n",
+		PR_IntervalToMilliseconds(prit));
+    }
+#endif /* PRLDAP_DEBUG */
+
+    return( prit );
+}
+
+
+static int LDAP_CALLBACK
+prldap_read( int s, void *buf, int bufsize,
+	struct lextiof_socket_private *socketarg )
+{
+    PRIntervalTime	prit;
+
+    prit = prldap_timeout2it( LDAP_X_IO_TIMEOUT_NO_TIMEOUT,
+			socketarg->prsock_io_max_timeout );
+    return( PR_Recv( PRLDAP_GET_PRFD(socketarg), buf, bufsize, 0, prit ));
+}
+
+
+static int LDAP_CALLBACK
+prldap_write( int s, const void *buf, int len,
+	struct lextiof_socket_private *socketarg )
+{
+    PRIntervalTime	prit;
+    char		*ptr = (char *)buf;
+    int			rest = len;
+
+    prit = prldap_timeout2it( LDAP_X_IO_TIMEOUT_NO_TIMEOUT,
+			socketarg->prsock_io_max_timeout );
+
+    while ( rest > 0 ) {
+	int rval;
+	if ( rest > PRLDAP_MAX_SEND_SIZE ) {
+	    len = PRLDAP_MAX_SEND_SIZE;
+	} else {
+	    len = rest;
+	}
+	/*
+	 * Note the 4th parameter (flags) to PR_Send() has been obsoleted and
+	 * must always be 0
+	 */
+	rval = PR_Send( PRLDAP_GET_PRFD(socketarg), ptr, len, 0, prit );
+	if ( 0 > rval ) {
+	    return rval;
+	}
+
+	if ( 0 == rval ) {
+	    break;
+	}
+
+	ptr += rval;
+	rest -= rval;
+    }
+
+    return (int)( ptr - (char *)buf );
+}
+
+
+struct prldap_eventmap_entry {
+    PRInt16	evm_nspr;	/* corresponding NSPR PR_Poll() event */
+    int		evm_ldap;	/* LDAP poll event */
+};
+
+static struct prldap_eventmap_entry prldap_eventmap[] = {
+    { PR_POLL_READ,	LDAP_X_POLLIN },
+    { PR_POLL_EXCEPT,	LDAP_X_POLLPRI },
+    { PR_POLL_WRITE,	LDAP_X_POLLOUT },
+    { PR_POLL_ERR,	LDAP_X_POLLERR },
+    { PR_POLL_HUP,	LDAP_X_POLLHUP },
+    { PR_POLL_NVAL,	LDAP_X_POLLNVAL },
+};
+
+#define PRLDAP_EVENTMAP_ENTRIES	\
+	sizeof(prldap_eventmap)/sizeof(struct prldap_eventmap_entry )
+
+static int LDAP_CALLBACK
+prldap_poll( LDAP_X_PollFD fds[], int nfds, int timeout,
+	struct lextiof_session_private *sessionarg )
+{
+    PRLDAPIOSessionArg	*prsessp = sessionarg;
+    PRPollDesc		*pds;
+    int			i, j, rc;
+
+    if ( NULL == prsessp ) {
+	prldap_set_system_errno( EINVAL );
+	return( -1 );
+    }
+
+    /* allocate or resize NSPR poll descriptor array */
+    if ( prsessp->prsess_pollds_count < nfds ) {
+	pds = prldap_safe_realloc( prsessp->prsess_pollds,
+		( nfds + PRLDAP_POLL_ARRAY_GROWTH )
+		* sizeof( PRPollDesc ));
+	if ( NULL == pds ) {
+	    prldap_set_system_errno( prldap_prerr2errno());
+	    return( -1 );
+	}
+	prsessp->prsess_pollds = pds;
+	prsessp->prsess_pollds_count = nfds + PRLDAP_POLL_ARRAY_GROWTH;
+    } else {
+	pds = prsessp->prsess_pollds;
+    }
+
+    /* populate NSPR poll info. based on LDAP info. */
+    for ( i = 0; i < nfds; ++i ) {
+	if ( NULL == fds[i].lpoll_socketarg ) {
+	    pds[i].fd = NULL;
+	} else {
+	    pds[i].fd = PRLDAP_GET_PRFD( fds[i].lpoll_socketarg );
+	}
+	pds[i].in_flags = pds[i].out_flags = 0;
+	if ( fds[i].lpoll_fd >= 0 ) {
+	    for ( j = 0; j < PRLDAP_EVENTMAP_ENTRIES; ++j ) {
+		if (( fds[i].lpoll_events & prldap_eventmap[j].evm_ldap )
+		    != 0 ) {
+			pds[i].in_flags |= prldap_eventmap[j].evm_nspr;
+		}
+	    }
+	}
+	fds[i].lpoll_revents = 0;	/* clear revents */
+    }
+
+    /* call PR_Poll() to do the real work */
+    rc = PR_Poll( pds, nfds,
+	    prldap_timeout2it( timeout, prsessp->prsess_io_max_timeout ));
+
+    /* populate LDAP info. based on NSPR results */
+    for ( i = 0; i < nfds; ++i ) {
+	if ( pds[i].fd != NULL ) {
+	    for ( j = 0; j < PRLDAP_EVENTMAP_ENTRIES; ++j ) {
+		if (( pds[i].out_flags & prldap_eventmap[j].evm_nspr )
+			!= 0 ) {
+		    fds[i].lpoll_revents |= prldap_eventmap[j].evm_ldap;
+		}
+	    }
+	}
+    }
+
+    return( rc );
+}
+
+
+/*
+ * Utility function to try one TCP connect()
+ * Returns 1 if successful and -1 if not.  Sets the NSPR fd inside prsockp.
+ */
+static int
+prldap_try_one_address( struct lextiof_socket_private *prsockp,
+    PRNetAddr *addrp, int timeout, unsigned long options )
+{
+    /*
+     * Open a TCP socket:
+     */
+    if (( prsockp->prsock_prfd = PR_OpenTCPSocket(
+		PR_NetAddrFamily(addrp) )) == NULL ) {
+	return( -1 );
+    }
+
+    /*
+     * Set nonblocking option if requested:
+     */
+    if ( 0 != ( options & LDAP_X_EXTIOF_OPT_NONBLOCKING )) {
+	PRSocketOptionData	optdata;
+
+	optdata.option = PR_SockOpt_Nonblocking;
+	optdata.value.non_blocking = PR_TRUE;
+	if ( PR_SetSocketOption( prsockp->prsock_prfd, &optdata )
+		    != PR_SUCCESS ) {
+	    prldap_set_system_errno( prldap_prerr2errno());
+	    PR_Close( prsockp->prsock_prfd );
+	    return( -1 );
+	}
+    }
+
+#ifdef PRLDAP_DEBUG
+    {
+	char	buf[ 256 ], *p, *fmtstr;
+
+	if ( PR_SUCCESS != PR_NetAddrToString( addrp, buf, sizeof(buf ))) {
+		strcpy( buf, "conversion failed!" );
+	}
+	if ( strncmp( buf, "::ffff:", 7 ) == 0 ) {
+		/* IPv4 address mapped into IPv6 address space */
+		p = buf + 7;
+		fmtstr = "prldap_try_one_address(): Trying %s:%d...\n";
+	} else {
+		p = buf;
+		fmtstr = "prldap_try_one_address(): Trying [%s]:%d...\n";
+	}
+	fprintf( stderr, fmtstr, p, PR_ntohs( addrp->ipv6.port ));
+    }
+#endif /* PRLDAP_DEBUG */
+
+    /*
+     * Try to open the TCP connection itself:
+     */
+    if ( PR_SUCCESS != PR_Connect( prsockp->prsock_prfd, addrp,
+                prldap_timeout2it( timeout, prsockp->prsock_io_max_timeout ))
+                && PR_IN_PROGRESS_ERROR != PR_GetError() ) {
+	PR_Close( prsockp->prsock_prfd );
+	prsockp->prsock_prfd = NULL;
+	return( -1 );
+    }
+
+#ifdef PRLDAP_DEBUG
+    fputs( "prldap_try_one_address(): Connected.\n", stderr );
+#endif /* PRLDAP_DEBUG */
+
+    /*
+     * Success.  Return a valid file descriptor (1 is always valid)
+     */
+    return( 1 );
+}
+
+
+/*
+ * XXXmcs: At present, this code ignores the timeout when doing DNS lookups.
+ */
+static int LDAP_CALLBACK
+prldap_connect( const char *hostlist, int defport, int timeout,
+	unsigned long options, struct lextiof_session_private *sessionarg,
+	struct lextiof_socket_private **socketargp )
+{
+    int					rc, parse_err, port;
+    char				*host;
+    struct ldap_x_hostlist_status	*status;
+    struct lextiof_socket_private	*prsockp;
+    PRNetAddr				addr;
+    PRAddrInfo 				*infop = NULL;
+
+    if ( 0 != ( options & LDAP_X_EXTIOF_OPT_SECURE )) {
+	prldap_set_system_errno( EINVAL );
+	return( -1 );
+    }
+
+    if ( NULL == ( prsockp = prldap_socket_arg_alloc( sessionarg ))) {
+	prldap_set_system_errno( prldap_prerr2errno());
+	return( -1 );
+    }
+
+    rc = -1;	/* pessimistic */
+    for ( parse_err = ldap_x_hostlist_first( hostlist, defport, &host, &port,
+		&status );
+		rc < 0 && LDAP_SUCCESS == parse_err && NULL != host;
+		parse_err = ldap_x_hostlist_next( &host, &port, status )) {
+	/*
+	 * First, call PR_GetAddrInfoByName; PR_GetAddrInfoByName could 
+	 * support both IPv4 and IPv6 addresses depending upon the system's
+	 * configuration.  All available addresses are returned and each of
+	 * them is examined in prldap_try_one_address till it succeeds.
+	 * Then, try converting the string address, in case the string
+	 * address was not successfully handled in PR_GetAddrInfoByName.
+	 */
+	if ( NULL != ( infop =
+	      PR_GetAddrInfoByName( host, PR_AF_UNSPEC, 
+				    (PR_AI_ADDRCONFIG|PR_AI_NOCANONNAME) ))) {
+	    void *enump = NULL;
+	    do {
+		memset( &addr, 0, sizeof( addr ));
+		enump = PR_EnumerateAddrInfo( enump, infop, port, &addr );
+		if ( NULL == enump ) {
+		    break;
+		}
+		rc = prldap_try_one_address( prsockp, &addr, timeout, options );
+	    } while ( rc < 0 );
+	    PR_FreeAddrInfo( infop );
+	} else if ( PR_SUCCESS == PR_StringToNetAddr( host, &addr )) {
+	    PRLDAP_SET_PORT( &addr, port );
+	    rc = prldap_try_one_address( prsockp, &addr, timeout, options );
+	}
+	ldap_memfree( host );
+    }
+
+    if ( host ) {
+		ldap_memfree( host );
+	}
+    ldap_x_hostlist_statusfree( status );
+
+    if ( rc < 0 ) {
+	prldap_set_system_errno( prldap_prerr2errno());
+	prldap_socket_arg_free( &prsockp );
+    } else {
+	*socketargp = prsockp;
+    }
+
+    return( rc );
+}
+
+
+static int LDAP_CALLBACK
+prldap_close( int s, struct lextiof_socket_private *socketarg )
+{
+    int		rc;
+
+    rc = 0;
+    if ( PR_Close( PRLDAP_GET_PRFD(socketarg)) != PR_SUCCESS ) {
+	rc = -1;
+	prldap_set_system_errno( prldap_prerr2errno());
+    }
+    prldap_socket_arg_free( &socketarg );
+
+    return( rc );
+}
+
+
+/*
+ * LDAP session handle creation callback.
+ *
+ * Allocate a session argument if not already done, and then call the
+ * thread's new handle function.
+ */
+static int LDAP_CALLBACK
+prldap_newhandle( LDAP *ld, struct lextiof_session_private *sessionarg )
+{
+
+    if ( NULL == sessionarg ) {
+	struct ldap_x_ext_io_fns	iofns;
+
+	memset( &iofns, 0, sizeof(iofns));
+	iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE;
+	if ( ldap_get_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS,
+		(void *)&iofns ) < 0 ) {
+	    return( ldap_get_lderrno( ld, NULL, NULL ));
+	}
+	if ( NULL ==
+		( iofns.lextiof_session_arg = prldap_session_arg_alloc())) {
+	    return( LDAP_NO_MEMORY );
+	}
+	if ( ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS,
+		    (void *)&iofns ) < 0 ) {
+	    return( ldap_get_lderrno( ld, NULL, NULL ));
+	}
+    }
+
+    return( LDAP_SUCCESS );
+}
+
+
+/* only called/installed if shared is non-zero. */
+static int LDAP_CALLBACK
+prldap_shared_newhandle( LDAP *ld, struct lextiof_session_private *sessionarg )
+{
+    int		rc;
+
+    if (( rc = prldap_newhandle( ld, sessionarg )) == LDAP_SUCCESS ) {
+	rc = prldap_thread_new_handle( ld, sessionarg );
+    }
+
+    return( rc );
+}
+
+
+static void LDAP_CALLBACK
+prldap_disposehandle( LDAP *ld, struct lextiof_session_private *sessionarg )
+{
+    prldap_session_arg_free( &sessionarg );
+}
+
+
+/* only called/installed if shared is non-zero */
+static void LDAP_CALLBACK
+prldap_shared_disposehandle( LDAP *ld,
+	struct lextiof_session_private *sessionarg )
+{
+    prldap_thread_dispose_handle( ld, sessionarg );
+    prldap_disposehandle( ld, sessionarg );
+}
+
+
+/*
+ * Allocate a session argument.
+ */
+static PRLDAPIOSessionArg *
+prldap_session_arg_alloc( void )
+{
+    PRLDAPIOSessionArg		*prsessp;
+
+    prsessp = PR_Calloc( 1, sizeof( PRLDAPIOSessionArg ));
+
+    if ( NULL != prsessp ) {
+	/* copy global defaults to the new session handle */
+	prsessp->prsess_io_max_timeout = prldap_default_io_max_timeout;
+    }
+
+    return( prsessp );
+}
+
+
+static void
+prldap_session_arg_free( PRLDAPIOSessionArg **prsesspp )
+{
+    if ( NULL != prsesspp && NULL != *prsesspp ) {
+	if ( NULL != (*prsesspp)->prsess_pollds ) {
+	    PR_Free( (*prsesspp)->prsess_pollds );
+	    (*prsesspp)->prsess_pollds = NULL;
+	}
+	PR_Free( *prsesspp );
+	*prsesspp = NULL;
+    }
+}
+
+
+/*
+ * Given an LDAP session handle, retrieve a session argument.
+ * Returns an LDAP error code.
+ */
+int
+prldap_session_arg_from_ld( LDAP *ld, PRLDAPIOSessionArg **sessargpp )
+{
+    struct ldap_x_ext_io_fns	iofns;
+
+    if ( NULL == ld || NULL == sessargpp ) {
+	/* XXXmcs: NULL ld's are not supported */
+	ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
+	return( LDAP_PARAM_ERROR );
+    }
+
+    memset( &iofns, 0, sizeof(iofns));
+    iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE;
+    if ( ldap_get_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, (void *)&iofns ) < 0 ) {
+	return( ldap_get_lderrno( ld, NULL, NULL ));
+    }
+
+    if ( NULL == iofns.lextiof_session_arg ) {
+	ldap_set_lderrno( ld, LDAP_LOCAL_ERROR, NULL, NULL );
+	return( LDAP_LOCAL_ERROR );
+    }
+
+    *sessargpp = iofns.lextiof_session_arg;
+    return( LDAP_SUCCESS );
+}
+
+
+/*
+ * Given an LDAP session handle, retrieve a socket argument.
+ * Returns an LDAP error code.
+ */
+int
+prldap_socket_arg_from_ld( LDAP *ld, PRLDAPIOSocketArg **sockargpp )
+{
+    Sockbuf *sbp;
+    struct lber_x_ext_io_fns    extiofns;
+
+    if ( NULL == ld || NULL == sockargpp ) {
+        /* XXXmcs: NULL ld's are not supported */
+        ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
+        return( LDAP_PARAM_ERROR );
+    }
+
+    if ( ldap_get_option( ld, LDAP_X_OPT_SOCKBUF, (void *)&sbp ) < 0 ) {
+        return( ldap_get_lderrno( ld, NULL, NULL ));
+    }
+
+    memset( &extiofns, 0, sizeof(extiofns));
+    extiofns.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE;
+    if ( ber_sockbuf_get_option( sbp, LBER_SOCKBUF_OPT_EXT_IO_FNS,
+        (void *)&extiofns ) < 0 ) {
+        return( ldap_get_lderrno( ld, NULL, NULL ));
+    }
+
+    if ( NULL == extiofns.lbextiofn_socket_arg ) {
+        ldap_set_lderrno( ld, LDAP_LOCAL_ERROR, NULL, NULL );
+        return( LDAP_LOCAL_ERROR );
+    }
+
+    *sockargpp = extiofns.lbextiofn_socket_arg;
+    return( LDAP_SUCCESS );
+}
+
+
+/*
+ * Allocate a socket argument.
+ */
+PRLDAPIOSocketArg *
+prldap_socket_arg_alloc( PRLDAPIOSessionArg *sessionarg )
+{
+    PRLDAPIOSocketArg		*prsockp;
+
+    prsockp = PR_Calloc( 1, sizeof( PRLDAPIOSocketArg ));
+
+    if ( NULL != prsockp && NULL != sessionarg ) {
+	/* copy socket defaults from the session */
+	prsockp->prsock_io_max_timeout = sessionarg->prsess_io_max_timeout;
+    }
+
+    return( prsockp );
+}
+
+
+static void
+prldap_socket_arg_free( PRLDAPIOSocketArg **prsockpp )
+{
+    if ( NULL != prsockpp && NULL != *prsockpp ) {
+	PR_Free( *prsockpp );
+	*prsockpp = NULL;
+    }
+}
+
+
+static void *
+prldap_safe_realloc( void *ptr, PRUint32 size )
+{
+    void	*p;
+
+    if ( NULL == ptr ) {
+	p = PR_Malloc( size );
+    } else {
+	p = PR_Realloc( ptr, size );
+    }
+
+    return( p );
+}
+
+
+
+/* returns an LDAP result code */
+int
+prldap_set_io_max_timeout( PRLDAPIOSessionArg *prsessp, int io_max_timeout )
+{
+    int	rc = LDAP_SUCCESS;	/* optimistic */
+
+    if ( NULL == prsessp ) {
+	prldap_default_io_max_timeout = io_max_timeout;
+    } else {
+	prsessp->prsess_io_max_timeout = io_max_timeout;
+    }
+
+    return( rc );
+}
+
+
+/* returns an LDAP result code */
+int
+prldap_get_io_max_timeout( PRLDAPIOSessionArg *prsessp, int *io_max_timeoutp )
+{
+    int	rc = LDAP_SUCCESS;	/* optimistic */
+
+    if ( NULL == io_max_timeoutp ) {
+	rc = LDAP_PARAM_ERROR;
+    } else if ( NULL == prsessp ) {
+	*io_max_timeoutp = prldap_default_io_max_timeout;
+    } else {
+	*io_max_timeoutp = prsessp->prsess_io_max_timeout;
+    }
+
+    return( rc );
+}
+
+/* Check if NSPR layer has been installed for a LDAP session.
+ * Simply check whether prldap_connect() I/O function is installed 
+ */
+PRBool
+prldap_is_installed( LDAP *ld )
+{
+    struct ldap_x_ext_io_fns iofns;
+
+    /* Retrieve current I/O functions */
+    memset( &iofns, 0, sizeof(iofns));
+    iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE;
+    if ( ld == NULL || ldap_get_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, (void *)&iofns )
+	 != 0 ||  iofns.lextiof_connect != prldap_connect ) 
+    {
+	return( PR_FALSE );
+    }
+    
+    return( PR_TRUE );
+}
+
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libprldap/ldappr-public.c
@@ -0,0 +1,454 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Public interface for libprldap -- use NSPR (Netscape Portable Runtime)
+ * I/O, threads, etc. with libldap.
+ *
+ */
+
+#include "ldappr-int.h"
+#include <private/pprio.h>
+
+/*
+ * Function: prldap_init().
+ *
+ * Create a new LDAP session handle, but with NSPR I/O, threading, and DNS
+ * functions installed.
+ *
+ * Pass a non-zero value for the 'shared' parameter if you plan to use
+ * this LDAP * handle from more than one thread.
+ *
+ * prldap_init() returns an LDAP session handle (or NULL if an error occurs).
+ */
+LDAP * LDAP_CALL
+prldap_init( const char *defhost, int defport, int shared )
+{
+    LDAP	*ld;
+
+    if (( ld = ldap_init( defhost, defport )) != NULL ) {
+	if ( prldap_install_routines( ld, shared ) != LDAP_SUCCESS ) {
+	    prldap_set_system_errno( EINVAL );	/* XXXmcs: just a guess! */
+	    ldap_unbind( ld );
+	    ld = NULL;
+	}
+    }
+
+    return( ld );
+}
+
+
+/*
+ * Function: prldap_install_routines().
+ *
+ * Install NSPR I/O, threading, and DNS functions so they will be used by
+ * 'ld'.
+ *
+ * If 'ld' is NULL, the functions are installed as the default functions
+ * for all new LDAP * handles).
+ *
+ * Pass a non-zero value for the 'shared' parameter if you plan to use
+ * this LDAP * handle from more than one thread.
+ *
+ * prldap_install_routines() returns an LDAP API error code (LDAP_SUCCESS
+ * if all goes well).
+ */
+int LDAP_CALL
+prldap_install_routines( LDAP *ld, int shared )
+{
+
+    if ( prldap_install_io_functions( ld, shared ) != 0
+		|| prldap_install_thread_functions( ld, shared ) != 0
+		|| prldap_install_dns_functions( ld ) != 0 ) {
+	return( ldap_get_lderrno( ld, NULL, NULL ));
+    }
+
+    return( LDAP_SUCCESS );
+}
+
+
+/*
+ * Function: prldap_set_session_option().
+ * 
+ * Given an LDAP session handle or a session argument such is passed to
+ * SOCKET, POLL, NEWHANDLE, or DISPOSEHANDLE extended I/O callbacks, set
+ * an option that affects the prldap layer.
+ * 
+ * If 'ld' and 'session" are both NULL, the option is set as the default
+ * for all new prldap sessions. 
+ * 
+ * Returns an LDAP API error code (LDAP_SUCCESS if all goes well).
+ */
+int LDAP_CALL
+prldap_set_session_option( LDAP *ld, void *sessionarg, int option, ... )
+{
+    int				rc = LDAP_SUCCESS;	/* optimistic */
+    PRLDAPIOSessionArg		*prsessp = NULL;
+    va_list			ap;
+
+    if ( NULL != ld ) {
+	if ( LDAP_SUCCESS !=
+		( rc = prldap_session_arg_from_ld( ld, &prsessp ))) {
+	    return( rc );
+	}
+    } else if ( NULL != sessionarg ) {
+	prsessp = (PRLDAPIOSessionArg *)sessionarg;
+    }
+
+    va_start( ap, option );
+    switch ( option ) {
+    case PRLDAP_OPT_IO_MAX_TIMEOUT:
+	rc = prldap_set_io_max_timeout( prsessp, va_arg( ap, int ));
+	break;
+    default:
+	rc = LDAP_PARAM_ERROR;
+    }
+    va_end( ap );
+
+    return( rc );
+}
+
+
+/*
+ * Function: prldap_get_session_option().
+ *
+ * Given an LDAP session handle or a session argument such is passed to
+ * SOCKET, POLL, NEWHANDLE, or DISPOSEHANDLE extended I/O callbacks, retrieve
+ * the setting for an option that affects the prldap layer.
+ *
+ * If 'ld' and 'session" are both NULL, the default option value for all new
+ * new prldap sessions is retrieved.
+ *
+ * Returns an LDAP API error code (LDAP_SUCCESS if all goes well).
+ */
+int LDAP_CALL prldap_get_session_option( LDAP *ld, void *sessionarg,
+        int option, ... )
+{
+    int				rc = LDAP_SUCCESS;	/* optimistic */
+    PRLDAPIOSessionArg		*prsessp = NULL;
+    va_list			ap;
+
+    if ( NULL != ld ) {
+	if ( LDAP_SUCCESS !=
+		( rc = prldap_session_arg_from_ld( ld, &prsessp ))) {
+	    return( rc );
+	}
+    } else if ( NULL != sessionarg ) {
+	prsessp = (PRLDAPIOSessionArg *)sessionarg;
+    }
+
+    va_start( ap, option );
+    switch ( option ) {
+    case PRLDAP_OPT_IO_MAX_TIMEOUT:
+	rc = prldap_get_io_max_timeout( prsessp, va_arg( ap, int * ));
+	break;
+    default:
+	rc = LDAP_PARAM_ERROR;
+    }
+    va_end( ap );
+
+    return( rc );
+}
+
+
+/*
+ * Function: prldap_set_session_info().
+ *
+ * Given an LDAP session handle, set some application-specific data.
+ *
+ * Returns an LDAP API error code (LDAP_SUCCESS if all goes well).
+ */
+int LDAP_CALL
+prldap_set_session_info( LDAP *ld, void *sessionarg, PRLDAPSessionInfo *seip )
+{
+    int				rc;
+    PRLDAPIOSessionArg		*prsessp;
+
+    if ( seip == NULL || PRLDAP_SESSIONINFO_SIZE != seip->seinfo_size ) {
+	ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
+	return( LDAP_PARAM_ERROR );
+    }
+
+    if ( NULL != ld ) {
+	if ( LDAP_SUCCESS !=
+		( rc = prldap_session_arg_from_ld( ld, &prsessp ))) {
+	    return( rc );
+	}
+    } else if ( NULL != sessionarg ) {
+	prsessp = (PRLDAPIOSessionArg *)sessionarg;
+    } else {
+	ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
+	return( LDAP_PARAM_ERROR );
+    }
+
+    prsessp->prsess_appdata = seip->seinfo_appdata;
+    return( LDAP_SUCCESS );
+}
+
+
+/*
+ * Function: prldap_get_session_info().
+ *
+ * Given an LDAP session handle, retrieve some application-specific data.
+ *
+ * Returns an LDAP API error code (LDAP_SUCCESS if all goes well, in
+ * which case the fields in the structure that seip points to are filled in).
+ */
+int LDAP_CALL
+prldap_get_session_info( LDAP *ld, void *sessionarg, PRLDAPSessionInfo *seip )
+{
+    int				rc;
+    PRLDAPIOSessionArg		*prsessp;
+
+    if ( seip == NULL || PRLDAP_SESSIONINFO_SIZE != seip->seinfo_size ) {
+	ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
+	return( LDAP_PARAM_ERROR );
+    }
+
+    if ( NULL != ld ) {
+	if ( LDAP_SUCCESS !=
+		( rc = prldap_session_arg_from_ld( ld, &prsessp ))) {
+	    return( rc );
+	}
+    } else if ( NULL != sessionarg ) {
+	prsessp = (PRLDAPIOSessionArg *)sessionarg;
+    } else {
+	ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
+	return( LDAP_PARAM_ERROR );
+    }
+
+    seip->seinfo_appdata = prsessp->prsess_appdata;
+    return( LDAP_SUCCESS );
+}
+
+
+/*
+ * Function: prldap_set_socket_info().
+ *
+ * Given an integer fd and a void * argument such as those passed to the
+ * extended I/O callback functions, set socket specific information.
+ *
+ * Returns an LDAP API error code (LDAP_SUCCESS if all goes well).
+ *
+ * Note: it is only safe to change soinfo_prfd from within the SOCKET
+ * extended I/O callback function.
+ */
+int LDAP_CALL
+prldap_set_socket_info( int fd, void *socketarg, PRLDAPSocketInfo *soip )
+{
+    PRLDAPIOSocketArg	*prsockp;
+
+    if ( NULL == socketarg || NULL == soip ||
+		PRLDAP_SOCKETINFO_SIZE != soip->soinfo_size ) {
+	return( LDAP_PARAM_ERROR );
+    }
+
+    prsockp = (PRLDAPIOSocketArg *)socketarg;
+    prsockp->prsock_prfd = soip->soinfo_prfd;
+    prsockp->prsock_appdata = soip->soinfo_appdata;
+
+    return( LDAP_SUCCESS );
+}
+
+
+/*
+ * Function: prldap_get_socket_info().
+ *
+ * Given an integer fd and a void * argument such as those passed to the
+ * extended I/O callback functions, retrieve socket specific information.
+ *
+ * Returns an LDAP API error code (LDAP_SUCCESS if all goes well, in
+ * which case the fields in the structure that soip points to are filled in).
+ */
+int LDAP_CALL
+prldap_get_socket_info( int fd, void *socketarg, PRLDAPSocketInfo *soip )
+{
+    PRLDAPIOSocketArg	*prsockp;
+
+    if ( NULL == socketarg || NULL == soip ||
+		PRLDAP_SOCKETINFO_SIZE != soip->soinfo_size ) {
+	return( LDAP_PARAM_ERROR );
+    }
+
+    prsockp = (PRLDAPIOSocketArg *)socketarg;
+    soip->soinfo_prfd = prsockp->prsock_prfd;
+    soip->soinfo_appdata = prsockp->prsock_appdata;
+
+    return( LDAP_SUCCESS );
+}
+
+
+/*
+ * Function: prldap_get_default_socket_info().
+ *
+ * Given an LDAP session handle, retrieve socket specific information.
+ * If ld is NULL, LDAP_PARAM_ERROR is returned.
+ *
+ * Returns an LDAP API error code (LDAP_SUCCESS if all goes well, in
+ * which case the fields in the structure that soip points to are filled in).
+ */
+int LDAP_CALL
+prldap_get_default_socket_info( LDAP *ld, PRLDAPSocketInfo *soip )
+{
+    int rc;
+    PRLDAPIOSocketArg *prsockp;
+
+
+    if ( NULL == soip || PRLDAP_SOCKETINFO_SIZE != soip->soinfo_size ) {
+        ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
+        return( LDAP_PARAM_ERROR );
+    }
+
+    if ( NULL != ld ) {
+        if ( LDAP_SUCCESS !=
+                ( rc = prldap_socket_arg_from_ld( ld, &prsockp ))) {
+            return( rc );
+        }
+    } else {
+        ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
+        return( LDAP_PARAM_ERROR );
+    }
+
+    soip->soinfo_prfd = prsockp->prsock_prfd;
+    soip->soinfo_appdata = prsockp->prsock_appdata;
+
+    return( LDAP_SUCCESS );
+}
+
+
+/*
+ * Function: prldap_set_default_socket_info().
+ *
+ * Given an LDAP session handle, set socket specific information.
+ * If ld is NULL, LDAP_PARAM_ERROR is returned.
+ *
+ * Returns an LDAP API error code (LDAP_SUCCESS if all goes well, in
+ * which case the fields in the structure that soip points to are filled in).
+ */
+int LDAP_CALL
+prldap_set_default_socket_info( LDAP *ld, PRLDAPSocketInfo *soip )
+{
+    int rc;
+    PRLDAPIOSocketArg *prsockp;
+
+
+    if ( NULL == soip || PRLDAP_SOCKETINFO_SIZE != soip->soinfo_size ) {
+        ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
+        return( LDAP_PARAM_ERROR );
+    }
+
+    if ( NULL != ld ) {
+        if ( LDAP_SUCCESS !=
+                ( rc = prldap_socket_arg_from_ld( ld, &prsockp ))) {
+            return( rc );
+        }
+    } else {
+        ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
+        return( LDAP_PARAM_ERROR );
+    }
+
+    prsockp->prsock_prfd = soip->soinfo_prfd;
+    prsockp->prsock_appdata = soip->soinfo_appdata;
+
+    return( LDAP_SUCCESS );
+}
+
+
+/*
+* Function: prldap_import_connection().
+* 
+* Given the LDAP handle the connection parameters for the
+* file descriptor are imported into NSPR layer.
+* 
+* Returns an LDAP API code (LDAP_SUCCESS) if all goes well.
+*/
+int LDAP_CALL
+prldap_import_connection (LDAP *ld)
+{
+	int rc = LDAP_SUCCESS; /* optimistic */
+	int shared = 1; /* Assume shared init */
+	LBER_SOCKET orig_socket = -1;
+	PRLDAPIOSessionArg *prsessp = NULL;
+	PRLDAPIOSocketArg *prsockp = NULL;
+	PRFileDesc *pr_socket = NULL;
+	
+	/* Check for invalid ld handle */
+    	if ( ld == NULL) {
+	    ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
+	    return( LDAP_PARAM_ERROR );
+    	}
+	
+	/* Retrieve TCP socket's integer file descriptor */
+    	if ( ldap_get_option( ld, LDAP_OPT_DESC, &orig_socket ) < 0 ) {
+	    return( ldap_get_lderrno( ld, NULL, NULL ));
+    	}
+	
+	/* Check for NSPR functions on ld */
+   	if ( prldap_is_installed(ld)) {	/* Error : NSPR already Installed */
+	    ldap_set_lderrno( ld, LDAP_LOCAL_ERROR, NULL, NULL );
+	    return( LDAP_LOCAL_ERROR );
+	}
+	
+    	if (LDAP_SUCCESS != (rc = prldap_install_routines(ld, shared))) {
+	    return( rc );
+    	}
+
+	if (LDAP_SUCCESS != (rc = prldap_session_arg_from_ld( ld, &prsessp ))) {
+	    return( rc );
+	}
+		
+	/* Get NSPR Socket Arg  */
+	if ( NULL == ( prsockp = prldap_socket_arg_alloc( prsessp ))) {
+	    ldap_set_lderrno( ld, LDAP_NO_MEMORY, NULL, NULL );
+	    return( LDAP_NO_MEMORY );
+	}
+	
+	/* Import file descriptor of connection made via ldap_init() */
+	if (NULL == (pr_socket = PR_ImportTCPSocket(orig_socket)) ) {
+	    ldap_set_lderrno( ld, LDAP_LOCAL_ERROR, NULL, NULL );
+	    return( LDAP_LOCAL_ERROR );
+	}
+
+	prsockp->prsock_prfd = pr_socket;
+
+	/* Set Socket Arg in Extended I/O Layer */
+	if ( ldap_set_option( ld, LDAP_X_OPT_SOCKETARG, prsockp) != 0 ) {
+	    return( ldap_get_lderrno( ld, NULL, NULL ));
+	}
+
+	return( rc );
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libprldap/ldappr-threads.c
@@ -0,0 +1,643 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Thread callback functions for libldap that use the NSPR (Netscape
+ * Portable Runtime) thread API.
+ *
+ */
+
+#include "ldappr-int.h"
+
+/*
+ * Macros:
+ */
+/*
+ * Grow thread private data arrays 10 elements at a time.
+ */
+#define PRLDAP_TPD_ARRAY_INCREMENT	10
+
+/*
+ * Structures and types:
+ */
+/*
+ * Structure used by libldap thread callbacks to maintain error information.
+ */
+typedef struct prldap_errorinfo {
+    int		plei_magic;	/* must be first in the structure */
+    int		plei_lderrno;
+    char	*plei_matched;
+    char	*plei_errmsg;
+} PRLDAP_ErrorInfo;
+
+#define PRLDAP_ERRORINFO_MAGIC	0x4D4F5A45	/* 'MOZE' */
+
+
+/*
+ * Structure used to maintain thread-private data. At the present time,
+ * only error info. is thread-private.  One of these structures is allocated
+ * for each thread.
+ */
+typedef struct prldap_tpd_header {
+    int			ptpdh_tpd_count;	/* # of data items allocated */
+    void		**ptpdh_dataitems;	/* array of data items */
+} PRLDAP_TPDHeader;
+
+/*
+ * Structure used by associate a PRLDAP thread-private data index with an
+ * LDAP session handle. One of these exists for each active LDAP session
+ * handle.
+ */
+typedef struct prldap_tpd_map {
+    LDAP			*prtm_ld;	/* non-NULL if in use */
+    PRUintn			prtm_index;	/* index into TPD array */
+    struct prldap_tpd_map	*prtm_next;
+} PRLDAP_TPDMap;
+
+
+
+/*
+ * Static Variables:
+ */
+/*
+ * prldap_map_list points to all of the PRLDAP_TPDMap structures
+ * we have ever allocated.  We recycle them as we open and close LDAP
+ * sessions.
+ */
+static PRLDAP_TPDMap *prldap_map_list = NULL;
+
+
+/*
+ * The prldap_map_mutex is used to protect access to the prldap_map_list.
+ */
+static PRLock	*prldap_map_mutex = NULL;
+
+/*
+ * The prldap_tpd_maxindex value is used to track the largest TPD array
+ * index we have used.
+ */
+static PRInt32	prldap_tpd_maxindex = -1;
+
+/*
+ * prldap_tpdindex is an NSPR thread private data index we use to
+ * maintain our own thread-private data. It is initialized inside
+ * prldap_init_tpd().
+ */
+static PRUintn	prldap_tpdindex = 0;
+
+/*
+ * The prldap_callonce_init_tpd structure is used by NSPR to ensure
+ * that prldap_init_tpd() is called at most once.
+ */
+static PRCallOnceType prldap_callonce_init_tpd = { 0, 0, 0 };
+
+
+/*
+ * Private function prototypes:
+ */
+static void prldap_set_ld_error( int err, char *matched, char *errmsg,
+	void *errorarg );
+static int prldap_get_ld_error( char **matchedp, char **errmsgp,
+	void *errorarg );
+static void *prldap_mutex_alloc( void );
+static void prldap_mutex_free( void *mutex );
+static int prldap_mutex_lock( void *mutex );
+static int prldap_mutex_unlock( void *mutex );
+static void *prldap_get_thread_id( void );
+static PRStatus prldap_init_tpd( void );
+static PRLDAP_TPDMap *prldap_allocate_map( LDAP *ld );
+static void prldap_return_map( PRLDAP_TPDMap *map );
+static PRUintn prldap_new_tpdindex( void );
+static int prldap_set_thread_private( PRInt32 tpdindex, void *priv );
+static void *prldap_get_thread_private( PRInt32 tpdindex );
+static PRLDAP_TPDHeader *prldap_tsd_realloc( PRLDAP_TPDHeader *tsdhdr,
+	int maxindex );
+static void prldap_tsd_destroy( void *priv );
+
+
+/*
+ * Install NSPR thread functions into ld (if ld is NULL, they are installed
+ * as the default functions for new LDAP * handles).
+ *
+ * Returns 0 if all goes well and -1 if not.
+ */
+int
+prldap_install_thread_functions( LDAP *ld, int shared )
+{
+    struct ldap_thread_fns		tfns;
+    struct ldap_extra_thread_fns	xtfns;
+
+    if ( PR_CallOnce( &prldap_callonce_init_tpd, prldap_init_tpd )
+		!= PR_SUCCESS ) {
+	ldap_set_lderrno( ld, LDAP_LOCAL_ERROR, NULL, NULL );
+	return( -1 );
+    }
+
+    /* set thread function pointers */
+    memset( &tfns, '\0', sizeof(struct ldap_thread_fns) );
+    tfns.ltf_get_errno = prldap_get_system_errno;
+    tfns.ltf_set_errno = prldap_set_system_errno;
+    if ( shared ) {
+	tfns.ltf_mutex_alloc = prldap_mutex_alloc;
+	tfns.ltf_mutex_free = prldap_mutex_free;
+	tfns.ltf_mutex_lock = prldap_mutex_lock;
+	tfns.ltf_mutex_unlock = prldap_mutex_unlock;
+	tfns.ltf_get_lderrno = prldap_get_ld_error;
+	tfns.ltf_set_lderrno = prldap_set_ld_error;
+	if ( ld != NULL ) {
+	    /*
+	     * If this is a real ld (i.e., we are not setting the global
+	     * defaults) allocate thread private data for error information.
+	     * If ld is NULL we do not do this here but it is done in
+	     * prldap_thread_new_handle().
+	     */
+	    if (( tfns.ltf_lderrno_arg = (void *)prldap_allocate_map( ld ))
+		    == NULL ) {
+		return( -1 );
+	    }
+	}
+    }
+
+    if ( ldap_set_option( ld, LDAP_OPT_THREAD_FN_PTRS,
+	    (void *)&tfns ) != 0 ) {
+	prldap_return_map( (PRLDAP_TPDMap *)tfns.ltf_lderrno_arg );
+	return( -1 );
+    }
+
+    /* set extended thread function pointers */
+    memset( &xtfns, '\0', sizeof(struct ldap_extra_thread_fns) );
+    xtfns.ltf_threadid_fn = prldap_get_thread_id;
+    if ( ldap_set_option( ld, LDAP_OPT_EXTRA_THREAD_FN_PTRS,
+	    (void *)&xtfns ) != 0 ) {
+	return( -1 );
+    }
+
+    return( 0 );
+}
+
+
+static void *
+prldap_mutex_alloc( void )
+{
+    return( (void *)PR_NewLock());
+}
+
+
+static void
+prldap_mutex_free( void *mutex )
+{
+    PR_DestroyLock( (PRLock *)mutex );
+}
+
+
+static int
+prldap_mutex_lock( void *mutex )
+{
+    PR_Lock( (PRLock *)mutex );
+    return( 0 );
+}
+
+
+static int
+prldap_mutex_unlock( void *mutex )
+{
+    if ( PR_Unlock( (PRLock *)mutex ) == PR_FAILURE ) {
+	return( -1 );
+    }
+
+    return( 0 );
+}
+
+
+static void *
+prldap_get_thread_id( void )
+{
+    return( (void *)PR_GetCurrentThread());
+}
+
+
+static int
+prldap_get_ld_error( char **matchedp, char **errmsgp, void *errorarg )
+{
+    PRLDAP_TPDMap	*map;
+    PRLDAP_ErrorInfo	*eip;
+
+    if (( map = (PRLDAP_TPDMap *)errorarg ) != NULL && ( eip =
+	    (PRLDAP_ErrorInfo *)prldap_get_thread_private(
+	    map->prtm_index )) != NULL ) {
+	if ( matchedp != NULL ) {
+	    *matchedp = eip->plei_matched;
+	}
+	if ( errmsgp != NULL ) {
+	    *errmsgp = eip->plei_errmsg;
+	}
+	return( eip->plei_lderrno );
+    } else {
+	if ( matchedp != NULL ) {
+	    *matchedp = NULL;
+	}
+	if ( errmsgp != NULL ) {
+	    *errmsgp = NULL;
+	}
+	return( LDAP_LOCAL_ERROR );	/* punt */
+    }
+}
+
+
+static void
+prldap_set_ld_error( int err, char *matched, char *errmsg, void *errorarg )
+{
+    PRLDAP_TPDMap	*map;
+    PRLDAP_ErrorInfo	*eip;
+
+    if (( map = (PRLDAP_TPDMap *)errorarg ) != NULL ) {
+	if (( eip = (PRLDAP_ErrorInfo *)prldap_get_thread_private(
+		map->prtm_index )) == NULL ) {
+	    /*
+	     * Error info. has not yet been allocated for this thread.
+	     * Do so now.  Note that we free this memory only for the
+	     * thread that calls prldap_thread_dispose_handle(), which
+	     * should be the one that called ldap_unbind() -- see
+	     * prldap_return_map().  Not freeing the memory used by
+	     * other threads is deemed acceptable since it will be
+	     * recycled and used by other LDAP sessions.  All of the
+	     * thread-private memory is freed when a thread exits
+	     * (inside the prldap_tsd_destroy() function).
+	     */
+	    eip = (PRLDAP_ErrorInfo *)PR_Calloc( 1,
+		    sizeof( PRLDAP_ErrorInfo ));
+	    if ( eip == NULL ) {
+		return;	/* punt */
+	    }
+	    eip->plei_magic = PRLDAP_ERRORINFO_MAGIC;
+	    (void)prldap_set_thread_private( map->prtm_index, eip );
+	}
+
+	eip->plei_lderrno = err;
+
+	if ( eip->plei_matched != NULL ) {
+	    ldap_memfree( eip->plei_matched );
+	}
+	eip->plei_matched = matched;
+
+	if ( eip->plei_errmsg != NULL ) {
+	    ldap_memfree( eip->plei_errmsg );
+	}
+	eip->plei_errmsg = errmsg;
+    }
+}
+
+
+/*
+ * Utility function to free a PRLDAP_ErrorInfo structure and everything
+ * it contains.
+ */
+static void
+prldap_free_errorinfo( PRLDAP_ErrorInfo *eip )
+{
+    if ( NULL != eip && PRLDAP_ERRORINFO_MAGIC == eip->plei_magic ) {
+	if ( eip->plei_matched != NULL ) {
+	    ldap_memfree( eip->plei_matched );
+	}
+	if ( eip->plei_errmsg != NULL ) {
+	    ldap_memfree( eip->plei_errmsg );
+	}
+
+	PR_Free( eip );
+    }
+}
+
+
+/*
+ * Called when a new LDAP * session handle is allocated.
+ * Allocate thread-private data for error information, but only if
+ * it has not already been allocated and the get_ld_error callback has
+ * been installed.  If ld is not NULL when prldap_install_thread_functions()
+ * is called, we will have already allocated the thread-private data there.
+ */
+int
+prldap_thread_new_handle( LDAP *ld, void *sessionarg )
+{
+    struct ldap_thread_fns	tfns;
+
+    if ( ldap_get_option( ld, LDAP_OPT_THREAD_FN_PTRS, (void *)&tfns ) != 0 ) {
+	return( LDAP_LOCAL_ERROR );
+    }
+
+    if ( tfns.ltf_lderrno_arg == NULL && tfns.ltf_get_lderrno != NULL ) {
+	if (( tfns.ltf_lderrno_arg = (void *)prldap_allocate_map( ld )) == NULL
+		|| ldap_set_option( ld, LDAP_OPT_THREAD_FN_PTRS,
+		(void *)&tfns ) != 0 ) {
+	    return( LDAP_LOCAL_ERROR );
+	}
+    }
+
+    return( LDAP_SUCCESS );
+}
+
+
+/*
+ * Called when an LDAP * session handle is being destroyed.
+ * Clean up our thread private data map.
+ */
+void
+prldap_thread_dispose_handle( LDAP *ld, void *sessionarg )
+{
+    struct ldap_thread_fns	tfns;
+
+    if ( ldap_get_option( ld, LDAP_OPT_THREAD_FN_PTRS,
+	    (void *)&tfns ) == 0 &&
+	    tfns.ltf_lderrno_arg != NULL ) {
+	prldap_return_map( (PRLDAP_TPDMap *)tfns.ltf_lderrno_arg );
+    }
+}
+
+
+static PRStatus
+prldap_init_tpd( void )
+{
+    if (( prldap_map_mutex = PR_NewLock()) == NULL || PR_NewThreadPrivateIndex(
+		&prldap_tpdindex, prldap_tsd_destroy ) != PR_SUCCESS ) {
+	return( PR_FAILURE );
+    }
+
+    prldap_map_list = NULL;
+
+    return( PR_SUCCESS );
+}
+
+
+/*
+ * Function: prldap_allocate_map()
+ * Description: allocate a thread-private data map to use for a new
+ *	LDAP session handle.
+ * Returns: a pointer to the TPD map or NULL if none available.
+ */
+static PRLDAP_TPDMap *
+prldap_allocate_map( LDAP *ld )
+{
+    PRLDAP_TPDMap	*map, *prevmap;
+
+    PR_Lock( prldap_map_mutex );
+
+    /*
+     * first look for a map that is already allocated but free to be re-used
+     */
+    prevmap = NULL;
+    for ( map = prldap_map_list; map != NULL; map = map->prtm_next ) {
+	if ( map->prtm_ld == NULL ) {
+	    break;
+	}
+	prevmap = map;
+    }
+
+    /*
+     * if none was found (map == NULL), try to allocate a new one and add it
+     * to the end of our global list.
+     */
+    if ( map == NULL ) {
+	PRUintn	tpdindex;
+
+	tpdindex = prldap_new_tpdindex();
+	map = (PRLDAP_TPDMap *)PR_Malloc( sizeof( PRLDAP_TPDMap ));
+	if ( map != NULL ) {
+	    map->prtm_index = tpdindex;
+	    map->prtm_next = NULL;
+	    if ( prevmap == NULL ) {
+		prldap_map_list = map;
+	    } else {
+		prevmap->prtm_next = map;
+	    }
+	}
+    }
+
+    if ( map != NULL ) {
+	map->prtm_ld = ld;	/* now marked as "in use" */
+
+	/*
+	 * If old thread-private error information exists, reset it. It may
+	 * have been left behind by an old LDAP session that was used by
+	 * this thread but disposed of by a different thread.
+	 */
+	if ( NULL != prldap_get_thread_private( map->prtm_index )) {
+	    prldap_set_ld_error( LDAP_SUCCESS, NULL, NULL, map );
+	}
+    }
+
+    PR_Unlock( prldap_map_mutex );
+
+    return( map );
+}
+
+
+/*
+ * Function: prldap_return_map()
+ * Description: return a thread-private data map to the pool of ones
+ *	available for re-use.
+ */
+static void
+prldap_return_map( PRLDAP_TPDMap *map )
+{
+    PRLDAP_ErrorInfo	*eip;
+
+    PR_Lock( prldap_map_mutex );
+
+    /*
+     * Dispose of thread-private LDAP error information.  Note that this
+     * only disposes of the memory consumed on THIS thread, but that is
+     * okay.  See the comment in prldap_set_ld_error() for the reason why.
+     */
+    if (( eip = (PRLDAP_ErrorInfo *)prldap_get_thread_private(
+		map->prtm_index )) != NULL &&
+		prldap_set_thread_private( map->prtm_index, NULL ) == 0 ) {
+	prldap_free_errorinfo( eip );
+    }
+
+    /* mark map as available for re-use */
+    map->prtm_ld = NULL;
+
+    PR_Unlock( prldap_map_mutex );
+}
+
+
+/*
+ * Function: prldap_new_tpdindex()
+ * Description: allocate a thread-private data index.
+ * Returns: the new index.
+ */
+static PRUintn
+prldap_new_tpdindex( void )
+{
+    PRUintn	tpdindex;
+
+    tpdindex = (PRUintn)PR_AtomicIncrement( &prldap_tpd_maxindex );
+    return( tpdindex );
+}
+
+
+/*
+ * Function: prldap_set_thread_private()
+ * Description: store a piece of thread-private data.
+ * Returns: 0 if successful and -1 if not.
+ */
+static int
+prldap_set_thread_private( PRInt32 tpdindex, void *priv )
+{
+    PRLDAP_TPDHeader	*tsdhdr;
+
+    if ( tpdindex > prldap_tpd_maxindex ) {
+	return( -1 );	/* bad index */ 
+    }
+
+    tsdhdr = (PRLDAP_TPDHeader *)PR_GetThreadPrivate( prldap_tpdindex );
+    if ( tsdhdr == NULL || tpdindex >= tsdhdr->ptpdh_tpd_count ) {
+	tsdhdr = prldap_tsd_realloc( tsdhdr, tpdindex );
+	if ( tsdhdr == NULL ) {
+	    return( -1 );	/* realloc failed */
+	}
+    }
+
+    tsdhdr->ptpdh_dataitems[ tpdindex ] = priv;
+    return( 0 );
+}
+
+
+/*
+ * Function: prldap_get_thread_private()
+ * Description: retrieve a piece of thread-private data.  If not set,
+ *	NULL is returned.
+ * Returns: 0 if successful and -1 if not.
+ */
+static void *
+prldap_get_thread_private( PRInt32 tpdindex )
+{
+    PRLDAP_TPDHeader	*tsdhdr;
+
+    tsdhdr = (PRLDAP_TPDHeader *)PR_GetThreadPrivate( prldap_tpdindex );
+    if ( tsdhdr == NULL ) {
+	return( NULL );	/* no thread private data */
+    }
+
+    if ( tpdindex >= tsdhdr->ptpdh_tpd_count
+		|| tsdhdr->ptpdh_dataitems == NULL ) {
+	return( NULL );	/* fewer data items than requested index */
+    }
+
+    return( tsdhdr->ptpdh_dataitems[ tpdindex ] );
+}
+
+
+/*
+ * Function: prldap_tsd_realloc()
+ * Description: enlarge the thread-private data array.
+ * Returns: the new PRLDAP_TPDHeader value (non-NULL if successful).
+ * Note: tsdhdr can be NULL (allocates a new PRLDAP_TPDHeader).
+ */
+static PRLDAP_TPDHeader *
+prldap_tsd_realloc( PRLDAP_TPDHeader *tsdhdr, int maxindex )
+{
+    void	*newdataitems = NULL;
+    int		count;
+
+    if ( tsdhdr == NULL ) {
+	/* allocate a new thread private data header */
+	if (( tsdhdr = PR_Calloc( 1, sizeof( PRLDAP_TPDHeader ))) == NULL ) {
+	    return( NULL );
+	}
+	(void)PR_SetThreadPrivate( prldap_tpdindex, tsdhdr );
+    }
+
+    /*
+     * Make the size of the new array the next highest multiple of
+     * the array increment value that is greater than maxindex.
+     */
+    count = PRLDAP_TPD_ARRAY_INCREMENT *
+		( 1 + ( maxindex / PRLDAP_TPD_ARRAY_INCREMENT ));
+
+    /* increase the size of the data item array if necessary */
+    if ( count > tsdhdr->ptpdh_tpd_count  ) {
+	newdataitems = (PRLDAP_ErrorInfo *)PR_Calloc( count, sizeof( void * ));
+	if ( newdataitems == NULL ) {
+	    return( NULL );
+	}
+	if ( tsdhdr->ptpdh_dataitems != NULL ) {	/* preserve old data */
+	    memcpy( newdataitems, tsdhdr->ptpdh_dataitems,
+			tsdhdr->ptpdh_tpd_count * sizeof( void * ));
+	    PR_Free( tsdhdr->ptpdh_dataitems );
+	}
+
+	tsdhdr->ptpdh_tpd_count = count;
+	tsdhdr->ptpdh_dataitems = newdataitems;
+    }
+
+    return( tsdhdr );
+}
+
+
+/*
+ * Function: prldap_tsd_destroy()
+ * Description: Free a thread-private data array. Installed as an NSPR TPD
+ *	destructor function
+ * Returns: nothing.
+ */
+static void
+prldap_tsd_destroy( void *priv )
+{
+    PRLDAP_TPDHeader	*tsdhdr;
+    PRLDAP_ErrorInfo	*eip;
+    int			i;
+
+    tsdhdr = (PRLDAP_TPDHeader *)priv;
+    if ( tsdhdr != NULL ) {
+	if ( tsdhdr->ptpdh_dataitems != NULL ) {
+	    for ( i = 0; i < tsdhdr->ptpdh_tpd_count; ++i ) {
+		if ( tsdhdr->ptpdh_dataitems[ i ] != NULL ) {
+		    eip = (PRLDAP_ErrorInfo *)tsdhdr->ptpdh_dataitems[ i ];
+		    if ( PRLDAP_ERRORINFO_MAGIC == eip->plei_magic ) {
+			prldap_free_errorinfo( eip );
+		    } else {
+			PR_Free( tsdhdr->ptpdh_dataitems[ i ] );
+		    }
+		    tsdhdr->ptpdh_dataitems[ i ] = NULL;
+		}
+	    }
+	    PR_Free( tsdhdr->ptpdh_dataitems );
+	    tsdhdr->ptpdh_dataitems = NULL;
+	}
+	PR_Free( tsdhdr );
+    }
+}
new file mode 100644
--- /dev/null
+++ b/ldap/c-sdk/libraries/libutil/Makefile.in
@@ -0,0 +1,85 @@
+# 
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+# 
+# The contents of this file are subject to the Mozilla Public License Version 
+# 1.1 (the "License"); you may not use this file except in compliance with 
+# the License. You may obtain a copy of the License at 
+# http://www.mozilla.org/MPL/
+# 
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+# 
+# The Original Code is mozilla.org code.
+# 
+# The Initial Developer of the Original Code is
+#   Rich Megginson <richm@stanfordalumni.org>
+# Portions created by the Initial Developer are Copyright (C) 2006
+# the Initial Developer. All Rights Reserved.
+# 
+# Contributor(s):
+# 
+# Alternatively, the contents of this file may be used under the terms of
+# either of the GNU General Public License Version 2 or later (the "GPL"),
+# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+# 
+# ***** END LICENSE BLOCK ***** 
+
+
+
+MOD_DEPTH	= ../../..
+srcdir		= @srcdir@
+topsrcdir 	= @top_srcdir@
+
+include $(MOD_DEPTH)/config/autoconf.mk
+include $(topsrcdir)/build.mk
+
+SRCS = getopt.c
+
+REALOBJS        = $(SRCS:.c=.$(OBJ_SUFFIX))
+
+UTILOBJDEST	= $(OBJDIR_NAME)
+OBJS		= $(addprefix $(UTILOBJDEST)/, $(REALOBJS))
+
+DISTHDIR	= $(DIST)/public/ldap
+HDIR		= $(topsrcdir)/ldap/include
+
+LIBUTIL	= $(addprefix $(UTILOBJDEST)/, \
+		  $(LIB_PREFIX)$(UTIL_LIBNAME).$(LIB_SUFFIX))
+
+INSTALLDIR      = $(DIST)/$(OBJDIR_NAME)
+
+include $(topsrcdir)/config/rules.mk
+
+DEFINES		+= $(DEFS)
+
+
+export::    $(OBJDEST) $(LIBDIR) $(OBJS) $(LIBUTIL)
+
+$(LIBDIR):
+	$(MKDIR) $(LIBDIR)
+
+$(LIBUTIL): $(OBJS) $(LIBDIR)
+	@echo ======= making $(LIBUTIL)
+ifdef SO_FILES_TO_REMOVE
+	-$(RM) $(SO_FILES_TO_REMOVE)
+endif
+	$(LINK_LIB)
+
+veryclean:: clean
+
+$(OBJDEST):
+	$(MKDIR) $(OBJDEST)
+
+export::	$(LIBUTIL)
+	$(INSTALL) -m 444 $(LIBUTIL) $(dist_libdir)
new file mode 100755
--- /dev/null
+++ b/ldap/c-sdk/libraries/libutil/getopt.c
@@ -0,0 +1,146 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ * 
+ * The contents of this file are subject to the Mozilla Public License Version 
+ * 1.1 (the "License"); you may not use this file except in compliance with 
+ * the License. You may obtain a copy of the License at 
+ * http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ * 
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ * 
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ * 
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that: (1) source distributions retain this entire copyright
+ * notice and comment, and (2) distributions including binaries display
+ * the following acknowledgement:  ``This product includes software
+ * developed by the University of California, Berkeley and its contributors''
+ * in the documentation or other materials provided with the distribution
+ * and in all advertising materials mentioning features or use of this
+ * software. Neither the name of the University nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifdef _WINDOWS
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getopt.c    4.12 (Berkeley) 6/1/90";
+#endif /* LIBC_SCCS and not lint */
+
+#include <windows.h>
+#include <stdio.h>
+#include <string.h>
+
+#define index strchr
+#define rindex strrchr
+
+/*
+ * get option letter from argument vector
+ */
+int     opterr = 1,             /* if error message should be printed */
+	optind = 1,             /* index into parent argv vector */
+	optopt;                 /* character checked for validity */
+char    *optarg;                /* argument associated with option */
+
+#define BADCH   (int)'?'
+#define EMSG    ""
+
+int getopt(int nargc, char *const *nargv, const char *ostr)
+{
+	static char *place = EMSG;              /* option letter processing */
+	register char *oli;                     /* option letter list index */
+	char *p;
+
+	if (!*place) {                          /* update scanning pointer */
+		if (optind >= nargc || *(place = nargv[optind]) != '-') {
+			place = EMSG;
+			return(EOF);
+		}
+		if (place[1] && *++place == '-') {      /* found "--" */
+			++optind;
+			place = EMSG;
+			return(EOF);
+		}
+	}                                       /* option letter okay? */
+	if ((optopt = (int)*place++) == (int)':' ||
+	    !(oli = index(ostr, optopt))) {
+		/*
+		 * if the user didn't specify '-' as an option,
+		 * assume it means EOF.
+		 */
+		if (optopt == (int)'-')
+			return(EOF);
+		if (!*place)
+			++optind;
+		if (opterr) {
+			if (!(p = rindex(*nargv, '/')))
+				p = *nargv;
+			else
+				++p;
+			(void)fprintf(stderr, "%s: illegal option -- %c\n",
+			    p, optopt);
+		}
+		return(BADCH);
+	}
+	if (*++oli != ':') {                    /* don't need argument */
+		optarg = NULL;
+		if (!*place)
+			++optind;
+	}
+	else {                                  /* need an argument */
+		if (*place)                     /* no white space */
+			optarg = place;
+		else if (nargc <= ++optind) {   /* no arg */
+			place = EMSG;
+			if (!(p = rindex(*nargv, '/')))
+				p = *nargv;
+			else
+				++p;
+			if (opterr)
+				(void)fprintf(stderr,
+				    "%s: option requires an argument -- %c\n",
+				    p, optopt);
+			return(BADCH);
+		}
+		else                            /* white space */
+			optarg = nargv[optind];
+		place = EMSG;
+		++optind;
+	}
+	return(optopt);                         /* dump back option letter */
+}
+
+#endif